LCOV - code coverage report
Current view: top level - source3/nmbd - nmbd_winsserver.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 24 979 2.5 %
Date: 2024-04-21 15:09:00 Functions: 4 40 10.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             :    NBT netbios routines and daemon - version 2
       4             : 
       5             :    Copyright (C) Jeremy Allison 1994-2005
       6             : 
       7             :    This program is free software; you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation; either version 3 of the License, or
      10             :    (at your option) any later version.
      11             : 
      12             :    This program is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : 
      20             :    Converted to store WINS data in a tdb. Dec 2005. JRA.
      21             : */
      22             : 
      23             : #include "includes.h"
      24             : #include "system/filesys.h"
      25             : #include "nmbd/nmbd.h"
      26             : #include "util_tdb.h"
      27             : #include "lib/util/util_file.h"
      28             : 
      29             : #define WINS_LIST "wins.dat"
      30             : #define WINS_VERSION 1
      31             : #define WINSDB_VERSION 1
      32             : 
      33             : /****************************************************************************
      34             :  We don't store the NetBIOS scope in the wins.tdb. We key off the (utf8) netbios
      35             :  name (65 bytes with the last byte being the name type).
      36             : *****************************************************************************/
      37             : 
      38             : TDB_CONTEXT *wins_tdb;
      39             : 
      40             : /****************************************************************************
      41             :  Delete all the temporary name records on the in-memory linked list.
      42             : *****************************************************************************/
      43             : 
      44           0 : static void wins_delete_all_tmp_in_memory_records(void)
      45             : {
      46           0 :         struct name_record *nr = NULL;
      47           0 :         struct name_record *nrnext = NULL;
      48             : 
      49             :         /* Delete all temporary name records on the wins subnet linked list. */
      50           0 :         for( nr = wins_server_subnet->namelist; nr; nr = nrnext) {
      51           0 :                 nrnext = nr->next;
      52           0 :                 DLIST_REMOVE(wins_server_subnet->namelist, nr);
      53           0 :                 SAFE_FREE(nr->data.ip);
      54           0 :                 SAFE_FREE(nr);
      55             :         }
      56           0 : }
      57             : 
      58             : /****************************************************************************
      59             :  Delete all the temporary 1b name records on the in-memory linked list.
      60             : *****************************************************************************/
      61             : 
      62           0 : static void wins_delete_all_1b_in_memory_records(void)
      63             : {
      64           0 :         struct name_record *nr = NULL;
      65           0 :         struct name_record *nrnext = NULL;
      66             : 
      67             :         /* Delete all temporary 1b name records on the wins subnet linked list. */
      68           0 :         for( nr = wins_server_subnet->namelist; nr; nr = nrnext) {
      69           0 :                 nrnext = nr->next;
      70           0 :                 if (nr->name.name_type == 0x1b) {
      71           0 :                         DLIST_REMOVE(wins_server_subnet->namelist, nr);
      72           0 :                         SAFE_FREE(nr->data.ip);
      73           0 :                         SAFE_FREE(nr);
      74             :                 }
      75             :         }
      76           0 : }
      77             : 
      78             : /****************************************************************************
      79             :  Convert a wins.tdb record to a struct name_record. Add in our lp_netbios_scope().
      80             : *****************************************************************************/
      81             : 
      82           0 : static struct name_record *wins_record_to_name_record(TDB_DATA key, TDB_DATA data)
      83             : {
      84           0 :         struct name_record *namerec = NULL;
      85             :         uint16_t nb_flags;
      86             :         unsigned char nr_src;
      87             :         uint32_t death_time, refresh_time;
      88             :         uint32_t id_low, id_high;
      89             :         uint32_t saddr;
      90             :         uint32_t wins_flags;
      91             :         uint32_t num_ips;
      92             :         size_t len;
      93             :         int i;
      94             : 
      95           0 :         if (data.dptr == NULL || data.dsize == 0) {
      96           0 :                 return NULL;
      97             :         }
      98             : 
      99             :         /* Min size is "wbddddddd" + 1 ip address (4). */
     100           0 :         if (data.dsize < 2 + 1 + (7*4) + 4) {
     101           0 :                 return NULL;
     102             :         }
     103             : 
     104           0 :         len = tdb_unpack(data.dptr, data.dsize,
     105             :                         "wbddddddd",
     106             :                         &nb_flags,
     107             :                         &nr_src,
     108             :                         &death_time,
     109             :                         &refresh_time,
     110             :                         &id_low,
     111             :                         &id_high,
     112             :                         &saddr,
     113             :                         &wins_flags,
     114             :                         &num_ips );
     115             : 
     116           0 :         namerec = SMB_MALLOC_P(struct name_record);
     117           0 :         if (!namerec) {
     118           0 :                 return NULL;
     119             :         }
     120           0 :         ZERO_STRUCTP(namerec);
     121             : 
     122           0 :         namerec->data.ip = SMB_MALLOC_ARRAY(struct in_addr, num_ips);
     123           0 :         if (!namerec->data.ip) {
     124           0 :                 SAFE_FREE(namerec);
     125           0 :                 return NULL;
     126             :         }
     127             : 
     128           0 :         namerec->subnet = wins_server_subnet;
     129           0 :         push_ascii_nstring(namerec->name.name, (const char *)key.dptr);
     130           0 :         namerec->name.name_type = key.dptr[sizeof(unstring)];
     131             :         /* Add the scope. */
     132           0 :         push_ascii(namerec->name.scope, lp_netbios_scope(), 64, STR_TERMINATE);
     133             : 
     134             :         /* We're using a byte-by-byte compare, so we must be sure that
     135             :          * unused space doesn't have garbage in it.
     136             :          */
     137             : 
     138           0 :         for( i = strlen( namerec->name.name ); i < sizeof( namerec->name.name ); i++ ) {
     139           0 :                 namerec->name.name[i] = '\0';
     140             :         }
     141           0 :         for( i = strlen( namerec->name.scope ); i < sizeof( namerec->name.scope ); i++ ) {
     142           0 :                 namerec->name.scope[i] = '\0';
     143             :         }
     144             : 
     145           0 :         namerec->data.nb_flags = nb_flags;
     146           0 :         namerec->data.source = (enum name_source)nr_src;
     147           0 :         namerec->data.death_time = (time_t)death_time;
     148           0 :         namerec->data.refresh_time = (time_t)refresh_time;
     149           0 :         namerec->data.id = id_low;
     150           0 :         namerec->data.id |= ((uint64_t)id_high << 32);
     151           0 :         namerec->data.wins_ip.s_addr = saddr;
     152           0 :         namerec->data.wins_flags = wins_flags,
     153           0 :         namerec->data.num_ips = num_ips;
     154             : 
     155           0 :         for (i = 0; i < num_ips; i++) {
     156           0 :                 namerec->data.ip[i].s_addr = IVAL(data.dptr, len + (i*4));
     157             :         }
     158             : 
     159           0 :         return namerec;
     160             : }
     161             : 
     162             : /****************************************************************************
     163             :  Convert a struct name_record to a wins.tdb record. Ignore the scope.
     164             : *****************************************************************************/
     165             : 
     166           0 : static TDB_DATA name_record_to_wins_record(const struct name_record *namerec)
     167             : {
     168             :         TDB_DATA data;
     169           0 :         size_t len = 0;
     170             :         int i;
     171           0 :         uint32_t id_low = (namerec->data.id & 0xFFFFFFFF);
     172           0 :         uint32_t id_high = (namerec->data.id >> 32) & 0xFFFFFFFF;
     173             : 
     174           0 :         ZERO_STRUCT(data);
     175             : 
     176           0 :         len = (2 + 1 + (7*4)); /* "wbddddddd" */
     177           0 :         len += (namerec->data.num_ips * 4);
     178             : 
     179           0 :         data.dptr = (uint8_t *)SMB_MALLOC(len);
     180           0 :         if (!data.dptr) {
     181           0 :                 return data;
     182             :         }
     183           0 :         data.dsize = len;
     184             : 
     185           0 :         len = tdb_pack(data.dptr, data.dsize, "wbddddddd",
     186           0 :                         namerec->data.nb_flags,
     187           0 :                         (unsigned char)namerec->data.source,
     188           0 :                         (uint32_t)namerec->data.death_time,
     189           0 :                         (uint32_t)namerec->data.refresh_time,
     190             :                         id_low,
     191             :                         id_high,
     192           0 :                         (uint32_t)namerec->data.wins_ip.s_addr,
     193           0 :                         (uint32_t)namerec->data.wins_flags,
     194           0 :                         (uint32_t)namerec->data.num_ips );
     195             : 
     196           0 :         for (i = 0; i < namerec->data.num_ips; i++) {
     197           0 :                 SIVAL(data.dptr, len + (i*4), namerec->data.ip[i].s_addr);
     198             :         }
     199             : 
     200           0 :         return data;
     201             : }
     202             : 
     203             : /****************************************************************************
     204             :  Create key. Key is UNIX codepage namestring (usually utf8 64 byte len) with 1 byte type.
     205             : *****************************************************************************/
     206             : 
     207           0 : static TDB_DATA name_to_key(const struct nmb_name *nmbname)
     208             : {
     209             :         static char keydata[sizeof(unstring) + 1];
     210             :         TDB_DATA key;
     211             : 
     212           0 :         memset(keydata, '\0', sizeof(keydata));
     213             : 
     214           0 :         pull_ascii_nstring(keydata, sizeof(unstring), nmbname->name);
     215           0 :         (void)strupper_m(keydata);
     216           0 :         keydata[sizeof(unstring)] = nmbname->name_type;
     217           0 :         key.dptr = (uint8_t *)keydata;
     218           0 :         key.dsize = sizeof(keydata);
     219             : 
     220           0 :         return key;
     221             : }
     222             : 
     223             : /****************************************************************************
     224             :  Lookup a given name in the wins.tdb and create a temporary malloc'ed data struct
     225             :  on the linked list. We will free this later in XXXX().
     226             : *****************************************************************************/
     227             : 
     228           0 : struct name_record *find_name_on_wins_subnet(const struct nmb_name *nmbname, bool self_only)
     229             : {
     230             :         TDB_DATA data, key;
     231           0 :         struct name_record *nr = NULL;
     232           0 :         struct name_record *namerec = NULL;
     233             : 
     234           0 :         if (!wins_tdb) {
     235           0 :                 return NULL;
     236             :         }
     237             : 
     238           0 :         key = name_to_key(nmbname);
     239           0 :         data = tdb_fetch(wins_tdb, key);
     240             : 
     241           0 :         if (data.dsize == 0) {
     242           0 :                 return NULL;
     243             :         }
     244             : 
     245           0 :         namerec = wins_record_to_name_record(key, data);
     246             : 
     247             :         /* done with the this */
     248             : 
     249           0 :         SAFE_FREE( data.dptr );
     250             : 
     251           0 :         if (!namerec) {
     252           0 :                 return NULL;
     253             :         }
     254             : 
     255             :         /* Self names only - these include permanent names. */
     256           0 :         if( self_only && (namerec->data.source != SELF_NAME) && (namerec->data.source != PERMANENT_NAME) ) {
     257           0 :                 DEBUG( 9, ( "find_name_on_wins_subnet: self name %s NOT FOUND\n", nmb_namestr(nmbname) ) );
     258           0 :                 SAFE_FREE(namerec->data.ip);
     259           0 :                 SAFE_FREE(namerec);
     260           0 :                 return NULL;
     261             :         }
     262             : 
     263             :         /* Search for this name record on the list. Replace it if found. */
     264             : 
     265           0 :         for( nr = wins_server_subnet->namelist; nr; nr = nr->next) {
     266           0 :                 if (memcmp(nmbname->name, nr->name.name, 16) == 0) {
     267             :                         /* Delete it. */
     268           0 :                         DLIST_REMOVE(wins_server_subnet->namelist, nr);
     269           0 :                         SAFE_FREE(nr->data.ip);
     270           0 :                         SAFE_FREE(nr);
     271           0 :                         break;
     272             :                 }
     273             :         }
     274             : 
     275           0 :         DLIST_ADD(wins_server_subnet->namelist, namerec);
     276           0 :         return namerec;
     277             : }
     278             : 
     279             : /****************************************************************************
     280             :  Overwrite or add a given name in the wins.tdb.
     281             : *****************************************************************************/
     282             : 
     283           0 : static bool store_or_replace_wins_namerec(const struct name_record *namerec, int tdb_flag)
     284             : {
     285             :         TDB_DATA key, data;
     286             :         int ret;
     287             : 
     288           0 :         if (!wins_tdb) {
     289           0 :                 return False;
     290             :         }
     291             : 
     292           0 :         key = name_to_key(&namerec->name);
     293           0 :         data = name_record_to_wins_record(namerec);
     294             : 
     295           0 :         if (data.dptr == NULL) {
     296           0 :                 return False;
     297             :         }
     298             : 
     299           0 :         ret = tdb_store(wins_tdb, key, data, tdb_flag);
     300             : 
     301           0 :         SAFE_FREE(data.dptr);
     302           0 :         return (ret == 0) ? True : False;
     303             : }
     304             : 
     305             : /****************************************************************************
     306             :  Overwrite a given name in the wins.tdb.
     307             : *****************************************************************************/
     308             : 
     309           0 : bool wins_store_changed_namerec(const struct name_record *namerec)
     310             : {
     311           0 :         return store_or_replace_wins_namerec(namerec, TDB_REPLACE);
     312             : }
     313             : 
     314             : /****************************************************************************
     315             :  Primary interface into creating and overwriting records in the wins.tdb.
     316             : *****************************************************************************/
     317             : 
     318           0 : bool add_name_to_wins_subnet(const struct name_record *namerec)
     319             : {
     320           0 :         return store_or_replace_wins_namerec(namerec, TDB_INSERT);
     321             : }
     322             : 
     323             : /****************************************************************************
     324             :  Delete a given name in the tdb and remove the temporary malloc'ed data struct
     325             :  on the linked list.
     326             : *****************************************************************************/
     327             : 
     328           0 : bool remove_name_from_wins_namelist(struct name_record *namerec)
     329             : {
     330             :         TDB_DATA key;
     331             :         int ret;
     332             : 
     333           0 :         if (!wins_tdb) {
     334           0 :                 return False;
     335             :         }
     336             : 
     337           0 :         key = name_to_key(&namerec->name);
     338           0 :         ret = tdb_delete(wins_tdb, key);
     339             : 
     340           0 :         DLIST_REMOVE(wins_server_subnet->namelist, namerec);
     341             : 
     342             :         /* namerec must be freed by the caller */
     343             : 
     344           0 :         return (ret == 0) ? True : False;
     345             : }
     346             : 
     347             : /****************************************************************************
     348             :  Dump out the complete namelist.
     349             : *****************************************************************************/
     350             : 
     351           0 : static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
     352             : {
     353           0 :         struct name_record *namerec = NULL;
     354           0 :         FILE *fp = (FILE *)state;
     355             : 
     356           0 :         if (kbuf.dsize != sizeof(unstring) + 1) {
     357           0 :                 return 0;
     358             :         }
     359             : 
     360           0 :         namerec = wins_record_to_name_record(kbuf, dbuf);
     361           0 :         if (!namerec) {
     362           0 :                 return 0;
     363             :         }
     364             : 
     365           0 :         dump_name_record(namerec, fp);
     366             : 
     367           0 :         SAFE_FREE(namerec->data.ip);
     368           0 :         SAFE_FREE(namerec);
     369           0 :         return 0;
     370             : }
     371             : 
     372           0 : void dump_wins_subnet_namelist(FILE *fp)
     373             : {
     374           0 :         tdb_traverse(wins_tdb, traverse_fn, (void *)fp);
     375           0 : }
     376             : 
     377             : /****************************************************************************
     378             :  Change the wins owner address in the record.
     379             : *****************************************************************************/
     380             : 
     381           0 : static void update_wins_owner(struct name_record *namerec, struct in_addr wins_ip)
     382             : {
     383           0 :         namerec->data.wins_ip=wins_ip;
     384           0 : }
     385             : 
     386             : /****************************************************************************
     387             :  Create the wins flags based on the nb flags and the input value.
     388             : *****************************************************************************/
     389             : 
     390           0 : static void update_wins_flag(struct name_record *namerec, int flags)
     391             : {
     392           0 :         namerec->data.wins_flags=0x0;
     393             : 
     394             :         /* if it's a group, it can be a normal or a special one */
     395           0 :         if (namerec->data.nb_flags & NB_GROUP) {
     396           0 :                 if (namerec->name.name_type==0x1C) {
     397           0 :                         namerec->data.wins_flags|=WINS_SGROUP;
     398             :                 } else {
     399           0 :                         if (namerec->data.num_ips>1) {
     400           0 :                                 namerec->data.wins_flags|=WINS_SGROUP;
     401             :                         } else {
     402           0 :                                 namerec->data.wins_flags|=WINS_NGROUP;
     403             :                         }
     404             :                 }
     405             :         } else {
     406             :                 /* can be unique or multi-homed */
     407           0 :                 if (namerec->data.num_ips>1) {
     408           0 :                         namerec->data.wins_flags|=WINS_MHOMED;
     409             :                 } else {
     410           0 :                         namerec->data.wins_flags|=WINS_UNIQUE;
     411             :                 }
     412             :         }
     413             : 
     414             :         /* the node type are the same bits */
     415           0 :         namerec->data.wins_flags|=namerec->data.nb_flags&NB_NODETYPEMASK;
     416             : 
     417             :         /* the static bit is elsewhere */
     418           0 :         if (namerec->data.death_time == PERMANENT_TTL) {
     419           0 :                 namerec->data.wins_flags|=WINS_STATIC;
     420             :         }
     421             : 
     422             :         /* and add the given bits */
     423           0 :         namerec->data.wins_flags|=flags;
     424             : 
     425           0 :         DEBUG(8,("update_wins_flag: nbflags: 0x%x, ttl: %d, flags: 0x%x, winsflags: 0x%x\n", 
     426             :                  namerec->data.nb_flags, (int)namerec->data.death_time, flags, namerec->data.wins_flags));
     427           0 : }
     428             : 
     429             : /****************************************************************************
     430             :  Return the general ID value and increase it if requested.
     431             : *****************************************************************************/
     432             : 
     433           0 : static void get_global_id_and_update(uint64_t *current_id, bool update)
     434             : {
     435             :         /*
     436             :          * it's kept as a static here, to prevent people from messing
     437             :          * with the value directly
     438             :          */
     439             : 
     440             :         static uint64_t general_id = 1;
     441             : 
     442           0 :         DEBUG(5,("get_global_id_and_update: updating version ID: %d\n", (int)general_id));
     443             : 
     444           0 :         *current_id = general_id;
     445             : 
     446           0 :         if (update) {
     447           0 :                 general_id++;
     448             :         }
     449           0 : }
     450             : 
     451             : /****************************************************************************
     452             :  Possibly call the WINS hook external program when a WINS change is made.
     453             :  Also stores the changed record back in the wins_tdb.
     454             : *****************************************************************************/
     455             : 
     456           0 : static void wins_hook(const char *operation, struct name_record *namerec, int ttl)
     457             : {
     458             :         const struct loadparm_substitution *lp_sub =
     459           0 :                 loadparm_s3_global_substitution();
     460           0 :         char *command = NULL;
     461           0 :         char *cmd = lp_wins_hook(talloc_tos(), lp_sub);
     462             :         char *p, *namestr;
     463             :         int i;
     464           0 :         TALLOC_CTX *ctx = talloc_tos();
     465             : 
     466           0 :         wins_store_changed_namerec(namerec);
     467             : 
     468           0 :         if (!cmd || !*cmd) {
     469           0 :                 return;
     470             :         }
     471             : 
     472           0 :         for (p=namerec->name.name; *p; p++) {
     473           0 :                 if (!(isalnum((int)*p) || strchr_m("._-",*p))) {
     474           0 :                         DEBUG(3,("not calling wins hook for invalid name %s\n", nmb_namestr(&namerec->name)));
     475           0 :                         return;
     476             :                 }
     477             :         }
     478             : 
     479             :         /* Use the name without the nametype (and scope) appended */
     480             : 
     481           0 :         namestr = nmb_namestr(&namerec->name);
     482           0 :         if ((p = strchr(namestr, '<'))) {
     483           0 :                 *p = 0;
     484             :         }
     485             : 
     486           0 :         command = talloc_asprintf(ctx,
     487             :                                 "%s %s %s %02x %d",
     488             :                                 cmd,
     489             :                                 operation,
     490             :                                 namestr,
     491             :                                 namerec->name.name_type,
     492             :                                 ttl);
     493           0 :         if (!command) {
     494           0 :                 return;
     495             :         }
     496             : 
     497           0 :         for (i=0;i<namerec->data.num_ips;i++) {
     498           0 :                 command = talloc_asprintf_append(command,
     499             :                                                 " %s",
     500           0 :                                                 inet_ntoa(namerec->data.ip[i]));
     501           0 :                 if (!command) {
     502           0 :                         return;
     503             :                 }
     504             :         }
     505             : 
     506           0 :         DEBUG(3,("calling wins hook for %s\n", nmb_namestr(&namerec->name)));
     507           0 :         smbrun(command, NULL, NULL);
     508           0 :         TALLOC_FREE(command);
     509             : }
     510             : 
     511             : /****************************************************************************
     512             : Determine if this packet should be allocated to the WINS server.
     513             : *****************************************************************************/
     514             : 
     515        7980 : bool packet_is_for_wins_server(struct packet_struct *packet)
     516             : {
     517        7980 :         struct nmb_packet *nmb = &packet->packet.nmb;
     518             : 
     519             :         /* Only unicast packets go to a WINS server. */
     520        7980 :         if((wins_server_subnet == NULL) || (nmb->header.nm_flags.bcast == True)) {
     521        7980 :                 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #1.\n"));
     522        7980 :                 return False;
     523             :         }
     524             : 
     525             :         /* Check for node status requests. */
     526           0 :         if (nmb->question.question_type != QUESTION_TYPE_NB_QUERY) {
     527           0 :                 return False;
     528             :         }
     529             : 
     530           0 :         switch(nmb->header.opcode) { 
     531             :                 /*
     532             :                  * A WINS server issues WACKS, not receives them.
     533             :                  */
     534           0 :                 case NMB_WACK_OPCODE:
     535           0 :                         DEBUG(10, ("packet_is_for_wins_server: failing WINS test #2 (WACK).\n"));
     536           0 :                         return False;
     537             :                 /*
     538             :                  * A WINS server only processes registration and
     539             :                  * release requests, not responses.
     540             :                  */
     541           0 :                 case NMB_NAME_REG_OPCODE:
     542             :                 case NMB_NAME_MULTIHOMED_REG_OPCODE:
     543             :                 case NMB_NAME_REFRESH_OPCODE_8: /* ambiguity in rfc1002 about which is correct. */
     544             :                 case NMB_NAME_REFRESH_OPCODE_9: /* WinNT uses 8 by default. */
     545           0 :                         if(nmb->header.response) {
     546           0 :                                 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #3 (response = 1).\n"));
     547           0 :                                 return False;
     548             :                         }
     549           0 :                         break;
     550             : 
     551           0 :                 case NMB_NAME_RELEASE_OPCODE:
     552           0 :                         if(nmb->header.response) {
     553           0 :                                 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #4 (response = 1).\n"));
     554           0 :                                 return False;
     555             :                         }
     556           0 :                         break;
     557             : 
     558             :                 /*
     559             :                  * Only process unicast name queries with rd = 1.
     560             :                  */
     561           0 :                 case NMB_NAME_QUERY_OPCODE:
     562           0 :                         if(!nmb->header.response && !nmb->header.nm_flags.recursion_desired) {
     563           0 :                                 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #5 (response = 1).\n"));
     564           0 :                                 return False;
     565             :                         }
     566           0 :                         break;
     567             :         }
     568             : 
     569           0 :         return True;
     570             : }
     571             : 
     572             : /****************************************************************************
     573             : Utility function to decide what ttl to give a register/refresh request.
     574             : *****************************************************************************/
     575             : 
     576           0 : static int get_ttl_from_packet(struct nmb_packet *nmb)
     577             : {
     578           0 :         int ttl = nmb->additional->ttl;
     579             : 
     580           0 :         if (ttl < lp_min_wins_ttl()) {
     581           0 :                 ttl = lp_min_wins_ttl();
     582             :         }
     583             : 
     584           0 :         if (ttl > lp_max_wins_ttl()) {
     585           0 :                 ttl = lp_max_wins_ttl();
     586             :         }
     587             : 
     588           0 :         return ttl;
     589             : }
     590             : 
     591             : /****************************************************************************
     592             : Load or create the WINS database.
     593             : *****************************************************************************/
     594             : 
     595          43 : bool initialise_wins(void)
     596             : {
     597          43 :         time_t time_now = time(NULL);
     598             :         FILE *fp;
     599             :         char line[1024];
     600             :         char *db_path;
     601             :         char *list_path;
     602             : 
     603          43 :         if(!lp_we_are_a_wins_server()) {
     604          43 :                 return True;
     605             :         }
     606             : 
     607           0 :         db_path = state_path(talloc_tos(), "wins.tdb");
     608           0 :         if (db_path == NULL) {
     609           0 :                 return false;
     610             :         }
     611             : 
     612             :         /* Open the wins.tdb. */
     613           0 :         wins_tdb = tdb_open_log(db_path, 0, TDB_DEFAULT|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
     614             :                         O_CREAT|O_RDWR, 0600);
     615           0 :         TALLOC_FREE(db_path);
     616           0 :         if (!wins_tdb) {
     617           0 :                 DEBUG(0,("initialise_wins: failed to open wins.tdb. Error was %s\n",
     618             :                         strerror(errno) ));
     619           0 :                 return False;
     620             :         }
     621             : 
     622           0 :         tdb_store_int32(wins_tdb, "WINSDB_VERSION", WINSDB_VERSION);
     623             : 
     624           0 :         add_samba_names_to_subnet(wins_server_subnet);
     625             : 
     626           0 :         list_path = state_path(talloc_tos(), WINS_LIST);
     627           0 :         if (list_path == NULL) {
     628           0 :                 tdb_close(wins_tdb);
     629           0 :                 return false;
     630             :         }
     631             : 
     632           0 :         fp = fopen(list_path, "r");
     633           0 :         TALLOC_FREE(list_path);
     634           0 :         if (fp == NULL) {
     635           0 :                 DEBUG(2,("initialise_wins: Can't open wins database file %s. Error was %s\n",
     636             :                         WINS_LIST, strerror(errno) ));
     637           0 :                 return True;
     638             :         }
     639             : 
     640           0 :         while (!feof(fp)) {
     641           0 :                 char *name_str = NULL;
     642           0 :                 char *ip_str = NULL;
     643           0 :                 char *ttl_str = NULL, *nb_flags_str = NULL;
     644             :                 unsigned int num_ips;
     645           0 :                 char *name = NULL;
     646           0 :                 struct in_addr *ip_list = NULL;
     647           0 :                 int type = 0;
     648             :                 int nb_flags;
     649             :                 int ttl;
     650             :                 const char *ptr;
     651           0 :                 char *p = NULL;
     652             :                 bool got_token;
     653             :                 bool was_ip;
     654             :                 int i;
     655             :                 unsigned int hash;
     656             :                 int version;
     657           0 :                 TALLOC_CTX *frame = NULL;
     658             : 
     659             :                 /* Read a line from the wins.dat file. Strips whitespace
     660             :                         from the beginning and end of the line.  */
     661           0 :                 if (!fgets_slash(NULL, line, sizeof(line), fp)) {
     662           0 :                         continue;
     663             :                 }
     664             : 
     665           0 :                 if (*line == '#') {
     666           0 :                         continue;
     667             :                 }
     668             : 
     669           0 :                 if (strncmp(line,"VERSION ", 8) == 0) {
     670           0 :                         if (sscanf(line,"VERSION %d %u", &version, &hash) != 2 ||
     671           0 :                                                 version != WINS_VERSION) {
     672           0 :                                 DEBUG(0,("Discarding invalid wins.dat file [%s]\n",line));
     673           0 :                                 fclose(fp);
     674           0 :                                 return True;
     675             :                         }
     676           0 :                         continue;
     677             :                 }
     678             : 
     679           0 :                 ptr = line;
     680             : 
     681             :                 /*
     682             :                  * Now we handle multiple IP addresses per name we need
     683             :                  * to iterate over the line twice. The first time to
     684             :                  * determine how many IP addresses there are, the second
     685             :                  * time to actually parse them into the ip_list array.
     686             :                  */
     687             : 
     688           0 :                 frame = talloc_stackframe();
     689           0 :                 if (!next_token_talloc(frame,&ptr,&name_str,NULL)) {
     690           0 :                         DEBUG(0,("initialise_wins: Failed to parse name when parsing line %s\n", line ));
     691           0 :                         TALLOC_FREE(frame);
     692           0 :                         continue;
     693             :                 }
     694             : 
     695           0 :                 if (!next_token_talloc(frame,&ptr,&ttl_str,NULL)) {
     696           0 :                         DEBUG(0,("initialise_wins: Failed to parse time to live when parsing line %s\n", line ));
     697           0 :                         TALLOC_FREE(frame);
     698           0 :                         continue;
     699             :                 }
     700             : 
     701             :                 /*
     702             :                  * Determine the number of IP addresses per line.
     703             :                  */
     704           0 :                 num_ips = 0;
     705             :                 do {
     706           0 :                         got_token = next_token_talloc(frame,&ptr,&ip_str,NULL);
     707           0 :                         was_ip = False;
     708             : 
     709           0 :                         if(got_token && strchr(ip_str, '.')) {
     710           0 :                                 num_ips++;
     711           0 :                                 was_ip = True;
     712             :                         }
     713           0 :                 } while(got_token && was_ip);
     714             : 
     715           0 :                 if(num_ips == 0) {
     716           0 :                         DEBUG(0,("initialise_wins: Missing IP address when parsing line %s\n", line ));
     717           0 :                         TALLOC_FREE(frame);
     718           0 :                         continue;
     719             :                 }
     720             : 
     721           0 :                 if(!got_token) {
     722           0 :                         DEBUG(0,("initialise_wins: Missing nb_flags when parsing line %s\n", line ));
     723           0 :                         TALLOC_FREE(frame);
     724           0 :                         continue;
     725             :                 }
     726             : 
     727             :                 /* Allocate the space for the ip_list. */
     728           0 :                 if((ip_list = SMB_MALLOC_ARRAY( struct in_addr, num_ips)) == NULL) {
     729           0 :                         DEBUG(0,("initialise_wins: Malloc fail !\n"));
     730           0 :                         fclose(fp);
     731           0 :                         TALLOC_FREE(frame);
     732           0 :                         return False;
     733             :                 }
     734             : 
     735             :                 /* Reset and re-parse the line. */
     736           0 :                 ptr = line;
     737           0 :                 next_token_talloc(frame,&ptr,&name_str,NULL);
     738           0 :                 next_token_talloc(frame,&ptr,&ttl_str,NULL);
     739           0 :                 for(i = 0; i < num_ips; i++) {
     740           0 :                         next_token_talloc(frame,&ptr, &ip_str, NULL);
     741           0 :                         ip_list[i] = interpret_addr2(ip_str);
     742             :                 }
     743           0 :                 next_token_talloc(frame,&ptr,&nb_flags_str,NULL);
     744             : 
     745             :                 /*
     746             :                  * Deal with SELF or REGISTER name encoding. Default is REGISTER
     747             :                  * for compatibility with old nmbds.
     748             :                  */
     749             : 
     750           0 :                 if(nb_flags_str[strlen(nb_flags_str)-1] == 'S') {
     751           0 :                         DEBUG(5,("initialise_wins: Ignoring SELF name %s\n", line));
     752           0 :                         SAFE_FREE(ip_list);
     753           0 :                         TALLOC_FREE(frame);
     754           0 :                         continue;
     755             :                 }
     756             : 
     757           0 :                 if(nb_flags_str[strlen(nb_flags_str)-1] == 'R') {
     758           0 :                         nb_flags_str[strlen(nb_flags_str)-1] = '\0';
     759             :                 }
     760             : 
     761             :                 /* Netbios name. # divides the name from the type (hex): netbios#xx */
     762           0 :                 name = name_str;
     763             : 
     764           0 :                 if((p = strchr(name,'#')) != NULL) {
     765           0 :                         *p = 0;
     766           0 :                         sscanf(p+1,"%x",&type);
     767             :                 }
     768             : 
     769             :                 /* Decode the netbios flags (hex) and the time-to-live (in seconds). */
     770           0 :                 sscanf(nb_flags_str,"%x",&nb_flags);
     771           0 :                 sscanf(ttl_str,"%d",&ttl);
     772             : 
     773             :                 /* add all entries that have 60 seconds or more to live */
     774           0 :                 if ((ttl - 60) > time_now || ttl == PERMANENT_TTL) {
     775           0 :                         if(ttl != PERMANENT_TTL) {
     776           0 :                                 ttl -= time_now;
     777             :                         }
     778             : 
     779           0 :                         DEBUG( 4, ("initialise_wins: add name: %s#%02x ttl = %d first IP %s flags = %2x\n",
     780             :                                 name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
     781             : 
     782           0 :                         (void)add_name_to_subnet( wins_server_subnet, name, type, nb_flags, 
     783             :                                         ttl, REGISTER_NAME, num_ips, ip_list );
     784             :                 } else {
     785           0 :                         DEBUG(4, ("initialise_wins: not adding name (ttl problem) "
     786             :                                 "%s#%02x ttl = %d first IP %s flags = %2x\n",
     787             :                                 name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
     788             :                 }
     789             : 
     790           0 :                 TALLOC_FREE(frame);
     791           0 :                 SAFE_FREE(ip_list);
     792             :         }
     793             : 
     794           0 :         fclose(fp);
     795           0 :         return True;
     796             : }
     797             : 
     798             : /****************************************************************************
     799             : Send a WINS WACK (Wait ACKnowledgement) response.
     800             : **************************************************************************/
     801             : 
     802           0 : static void send_wins_wack_response(int ttl, struct packet_struct *p)
     803             : {
     804           0 :         struct nmb_packet *nmb = &p->packet.nmb;
     805             :         unsigned char rdata[2];
     806             : 
     807           0 :         rdata[0] = rdata[1] = 0;
     808             : 
     809             :         /* Taken from nmblib.c - we need to send back almost
     810             :                 identical bytes from the requesting packet header. */
     811             : 
     812           0 :         rdata[0] = (nmb->header.opcode & 0xF) << 3;
     813           0 :         if (nmb->header.nm_flags.authoritative && nmb->header.response) {
     814           0 :                 rdata[0] |= 0x4;
     815             :         }
     816           0 :         if (nmb->header.nm_flags.trunc) {
     817           0 :                 rdata[0] |= 0x2;
     818             :         }
     819           0 :         if (nmb->header.nm_flags.recursion_desired) {
     820           0 :                 rdata[0] |= 0x1;
     821             :         }
     822           0 :         if (nmb->header.nm_flags.recursion_available && nmb->header.response) {
     823           0 :                 rdata[1] |= 0x80;
     824             :         }
     825           0 :         if (nmb->header.nm_flags.bcast) {
     826           0 :                 rdata[1] |= 0x10;
     827             :         }
     828             : 
     829           0 :         reply_netbios_packet(p,                                /* Packet to reply to. */
     830             :                                 0,                             /* Result code. */
     831             :                                 NMB_WAIT_ACK,                  /* nmbd type code. */
     832             :                                 NMB_WACK_OPCODE,               /* opcode. */
     833             :                                 ttl,                           /* ttl. */
     834             :                                 (char *)rdata,                 /* data to send. */
     835             :                                 2);                            /* data length. */
     836           0 : }
     837             : 
     838             : /****************************************************************************
     839             : Send a WINS name registration response.
     840             : **************************************************************************/
     841             : 
     842           0 : static void send_wins_name_registration_response(int rcode, int ttl, struct packet_struct *p)
     843             : {
     844           0 :         struct nmb_packet *nmb = &p->packet.nmb;
     845             :         char rdata[6];
     846             : 
     847           0 :         memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
     848             : 
     849           0 :         reply_netbios_packet(p,                                /* Packet to reply to. */
     850             :                                 rcode,                         /* Result code. */
     851             :                                 WINS_REG,                      /* nmbd type code. */
     852             :                                 NMB_NAME_REG_OPCODE,           /* opcode. */
     853             :                                 ttl,                           /* ttl. */
     854             :                                 rdata,                         /* data to send. */
     855             :                                 6);                            /* data length. */
     856           0 : }
     857             : 
     858             : /***********************************************************************
     859             :  Deal with a name refresh request to a WINS server.
     860             : ************************************************************************/
     861             : 
     862           0 : void wins_process_name_refresh_request( struct subnet_record *subrec,
     863             :                                         struct packet_struct *p )
     864             : {
     865           0 :         struct nmb_packet *nmb = &p->packet.nmb;
     866           0 :         struct nmb_name *question = &nmb->question.question_name;
     867           0 :         bool bcast = nmb->header.nm_flags.bcast;
     868           0 :         uint16_t nb_flags = get_nb_flags(nmb->additional->rdata);
     869           0 :         bool group = (nb_flags & NB_GROUP) ? True : False;
     870           0 :         struct name_record *namerec = NULL;
     871           0 :         int ttl = get_ttl_from_packet(nmb);
     872             :         struct in_addr from_ip;
     873             :         struct in_addr our_fake_ip;
     874             : 
     875           0 :         our_fake_ip = interpret_addr2("0.0.0.0");
     876           0 :         putip( (char *)&from_ip, &nmb->additional->rdata[2] );
     877             : 
     878           0 :         if(bcast) {
     879             :                 /*
     880             :                  * We should only get unicast name refresh packets here.
     881             :                  * Anyone trying to refresh broadcast should not be going
     882             :                  * to a WINS server.  Log an error here.
     883             :                  */
     884           0 :                 if( DEBUGLVL( 0 ) ) {
     885           0 :                         dbgtext( "wins_process_name_refresh_request: " );
     886           0 :                         dbgtext( "Broadcast name refresh request received " );
     887           0 :                         dbgtext( "for name %s ", nmb_namestr(question) );
     888           0 :                         dbgtext( "from IP %s ", inet_ntoa(from_ip) );
     889           0 :                         dbgtext( "on subnet %s.  ", subrec->subnet_name );
     890           0 :                         dbgtext( "Error - Broadcasts should not be sent " );
     891           0 :                         dbgtext( "to a WINS server\n" );
     892             :                 }
     893           0 :                 return;
     894             :         }
     895             : 
     896           0 :         if( DEBUGLVL( 3 ) ) {
     897           0 :                 dbgtext( "wins_process_name_refresh_request: " );
     898           0 :                 dbgtext( "Name refresh for name %s IP %s\n",
     899             :                          nmb_namestr(question), inet_ntoa(from_ip) );
     900             :         }
     901             : 
     902             :         /* 
     903             :          * See if the name already exists.
     904             :          * If not, handle it as a name registration and return.
     905             :          */
     906           0 :         namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
     907             : 
     908             :         /*
     909             :          * If this is a refresh request and the name doesn't exist then
     910             :          * treat it like a registration request. This allows us to recover 
     911             :          * from errors (tridge)
     912             :          */
     913           0 :         if(namerec == NULL) {
     914           0 :                 if( DEBUGLVL( 3 ) ) {
     915           0 :                         dbgtext( "wins_process_name_refresh_request: " );
     916           0 :                         dbgtext( "Name refresh for name %s ",
     917             :                                  nmb_namestr( question ) );
     918           0 :                         dbgtext( "and the name does not exist.  Treating " );
     919           0 :                         dbgtext( "as registration.\n" );
     920             :                 }
     921           0 :                 wins_process_name_registration_request(subrec,p);
     922           0 :                 return;
     923             :         }
     924             : 
     925             :         /*
     926             :          * if the name is present but not active, simply remove it
     927             :          * and treat the refresh request as a registration & return.
     928             :          */
     929           0 :         if (namerec != NULL && !WINS_STATE_ACTIVE(namerec)) {
     930           0 :                 if( DEBUGLVL( 5 ) ) {
     931           0 :                         dbgtext( "wins_process_name_refresh_request: " );
     932           0 :                         dbgtext( "Name (%s) in WINS ", nmb_namestr(question) );
     933           0 :                         dbgtext( "was not active - removing it.\n" );
     934             :                 }
     935           0 :                 remove_name_from_namelist( subrec, namerec );
     936           0 :                 namerec = NULL;
     937           0 :                 wins_process_name_registration_request( subrec, p );
     938           0 :                 return;
     939             :         }
     940             : 
     941             :         /*
     942             :          * Check that the group bits for the refreshing name and the
     943             :          * name in our database match.  If not, refuse the refresh.
     944             :          * [crh:  Why RFS_ERR instead of ACT_ERR? Is this what MS does?]
     945             :          */
     946           0 :         if( (namerec != NULL) &&
     947           0 :             ( (group && !NAME_GROUP(namerec))
     948           0 :            || (!group && NAME_GROUP(namerec)) ) ) {
     949           0 :                 if( DEBUGLVL( 3 ) ) {
     950           0 :                         dbgtext( "wins_process_name_refresh_request: " );
     951           0 :                         dbgtext( "Name %s ", nmb_namestr(question) );
     952           0 :                         dbgtext( "group bit = %s does not match ",
     953             :                                  group ? "True" : "False" );
     954           0 :                         dbgtext( "group bit in WINS for this name.\n" );
     955             :                 }
     956           0 :                 send_wins_name_registration_response(RFS_ERR, 0, p);
     957           0 :                 return;
     958             :         }
     959             : 
     960             :         /*
     961             :          * For a unique name check that the person refreshing the name is
     962             :          * one of the registered IP addresses. If not - fail the refresh.
     963             :          * Do the same for group names with a type of 0x1c.
     964             :          * Just return success for unique 0x1d refreshes. For normal group
     965             :          * names update the ttl and return success.
     966             :          */
     967           0 :         if( (!group || (group && (question->name_type == 0x1c)))
     968           0 :                         && find_ip_in_name_record(namerec, from_ip) ) {
     969             :                 /*
     970             :                  * Update the ttl.
     971             :                  */
     972           0 :                 update_name_ttl(namerec, ttl);
     973             : 
     974             :                 /*
     975             :                  * if the record is a replica:
     976             :                  * we take ownership and update the version ID.
     977             :                  */
     978           0 :                 if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
     979           0 :                         update_wins_owner(namerec, our_fake_ip);
     980           0 :                         get_global_id_and_update(&namerec->data.id, True);
     981             :                 }
     982             : 
     983           0 :                 send_wins_name_registration_response(0, ttl, p);
     984           0 :                 wins_hook("refresh", namerec, ttl);
     985           0 :                 return;
     986           0 :         } else if((group && (question->name_type == 0x1c))) {
     987             :                 /*
     988             :                  * Added by crh for bug #1079.
     989             :                  * Fix from Bert Driehuis
     990             :                  */
     991           0 :                 if( DEBUGLVL( 3 ) ) {
     992           0 :                         dbgtext( "wins_process_name_refresh_request: " );
     993           0 :                         dbgtext( "Name refresh for name %s, ",
     994             :                                  nmb_namestr(question) );
     995           0 :                         dbgtext( "but IP address %s ", inet_ntoa(from_ip) );
     996           0 :                         dbgtext( "is not yet associated with " );
     997           0 :                         dbgtext( "that name. Treating as registration.\n" );
     998             :                 }
     999           0 :                 wins_process_name_registration_request(subrec,p);
    1000           0 :                 return;
    1001           0 :         } else if(group) {
    1002             :                 /* 
    1003             :                  * Normal groups are all registered with an IP address of
    1004             :                  * 255.255.255.255  so we can't search for the IP address.
    1005             :                  */
    1006           0 :                 update_name_ttl(namerec, ttl);
    1007           0 :                 wins_hook("refresh", namerec, ttl);
    1008           0 :                 send_wins_name_registration_response(0, ttl, p);
    1009           0 :                 return;
    1010           0 :         } else if(!group && (question->name_type == 0x1d)) {
    1011             :                 /*
    1012             :                  * Special name type - just pretend the refresh succeeded.
    1013             :                  */
    1014           0 :                 send_wins_name_registration_response(0, ttl, p);
    1015           0 :                 return;
    1016             :         } else {
    1017             :                 /*
    1018             :                  * Fail the refresh.
    1019             :                  */
    1020           0 :                 if( DEBUGLVL( 3 ) ) {
    1021           0 :                         dbgtext( "wins_process_name_refresh_request: " );
    1022           0 :                         dbgtext( "Name refresh for name %s with IP %s ",
    1023             :                                  nmb_namestr(question), inet_ntoa(from_ip) );
    1024           0 :                         dbgtext( "and is IP is not known to the name.\n" );
    1025             :                 }
    1026           0 :                 send_wins_name_registration_response(RFS_ERR, 0, p);
    1027           0 :                 return;
    1028             :         }
    1029             : }
    1030             : 
    1031             : /***********************************************************************
    1032             :  Deal with a name registration request query success to a client that
    1033             :  owned the name.
    1034             : 
    1035             :  We have a locked pointer to the original packet stashed away in the
    1036             :  userdata pointer. The success here is actually a failure as it means
    1037             :  the client we queried wants to keep the name, so we must return
    1038             :  a registration failure to the original requester.
    1039             : ************************************************************************/
    1040             : 
    1041           0 : static void wins_register_query_success(struct subnet_record *subrec,
    1042             :                                              struct userdata_struct *userdata,
    1043             :                                              struct nmb_name *question_name,
    1044             :                                              struct in_addr ip,
    1045             :                                              struct res_rec *answers)
    1046             : {
    1047             :         struct packet_struct *orig_reg_packet;
    1048             : 
    1049           0 :         memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
    1050             : 
    1051           0 :         DEBUG(3,("wins_register_query_success: Original client at IP %s still wants the \
    1052             : name %s. Rejecting registration request.\n", inet_ntoa(ip), nmb_namestr(question_name) ));
    1053             : 
    1054           0 :         send_wins_name_registration_response(ACT_ERR, 0, orig_reg_packet);
    1055             : 
    1056           0 :         orig_reg_packet->locked = False;
    1057           0 :         free_packet(orig_reg_packet);
    1058           0 : }
    1059             : 
    1060             : /***********************************************************************
    1061             :  Deal with a name registration request query failure to a client that
    1062             :  owned the name.
    1063             : 
    1064             :  We have a locked pointer to the original packet stashed away in the
    1065             :  userdata pointer. The failure here is actually a success as it means
    1066             :  the client we queried didn't want to keep the name, so we can remove
    1067             :  the old name record and then successfully add the new name.
    1068             : ************************************************************************/
    1069             : 
    1070           0 : static void wins_register_query_fail(struct subnet_record *subrec,
    1071             :                                           struct response_record *rrec,
    1072             :                                           struct nmb_name *question_name,
    1073             :                                           int rcode)
    1074             : {
    1075           0 :         struct userdata_struct *userdata = rrec->userdata;
    1076             :         struct packet_struct *orig_reg_packet;
    1077           0 :         struct name_record *namerec = NULL;
    1078             : 
    1079           0 :         memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
    1080             : 
    1081             :         /*
    1082             :          * We want to just add the name, as we now know the original owner
    1083             :          * didn't want it. But we can't just do that as an arbitrary
    1084             :          * amount of time may have taken place between the name query
    1085             :          * request and this timeout/error response. So we check that
    1086             :          * the name still exists and is in the same state - if so
    1087             :          * we remove it and call wins_process_name_registration_request()
    1088             :          * as we know it will do the right thing now.
    1089             :          */
    1090             : 
    1091           0 :         namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
    1092             : 
    1093           0 :         if ((namerec != NULL) && (namerec->data.source == REGISTER_NAME) &&
    1094           0 :                         ip_equal_v4(rrec->packet->ip, *namerec->data.ip)) {
    1095           0 :                 remove_name_from_namelist( subrec, namerec);
    1096           0 :                 namerec = NULL;
    1097             :         }
    1098             : 
    1099           0 :         if(namerec == NULL) {
    1100           0 :                 wins_process_name_registration_request(subrec, orig_reg_packet);
    1101             :         } else {
    1102           0 :                 DEBUG(2,("wins_register_query_fail: The state of the WINS database changed between "
    1103             :                         "querying for name %s in order to replace it and this reply.\n",
    1104             :                         nmb_namestr(question_name) ));
    1105             :         }
    1106             : 
    1107           0 :         orig_reg_packet->locked = False;
    1108           0 :         free_packet(orig_reg_packet);
    1109           0 : }
    1110             : 
    1111             : /***********************************************************************
    1112             :  Deal with a name registration request to a WINS server.
    1113             : 
    1114             :  Use the following pseudocode :
    1115             : 
    1116             :  registering_group
    1117             :      |
    1118             :      |
    1119             :      +--------name exists
    1120             :      |                  |
    1121             :      |                  |
    1122             :      |                  +--- existing name is group
    1123             :      |                  |                      |
    1124             :      |                  |                      |
    1125             :      |                  |                      +--- add name (return).
    1126             :      |                  |
    1127             :      |                  |
    1128             :      |                  +--- exiting name is unique
    1129             :      |                                         |
    1130             :      |                                         |
    1131             :      |                                         +--- query existing owner (return).
    1132             :      |
    1133             :      |
    1134             :      +--------name doesn't exist
    1135             :                         |
    1136             :                         |
    1137             :                         +--- add name (return).
    1138             : 
    1139             :  registering_unique
    1140             :      |
    1141             :      |
    1142             :      +--------name exists
    1143             :      |                  |
    1144             :      |                  |
    1145             :      |                  +--- existing name is group 
    1146             :      |                  |                      |
    1147             :      |                  |                      |
    1148             :      |                  |                      +--- fail add (return).
    1149             :      |                  | 
    1150             :      |                  |
    1151             :      |                  +--- exiting name is unique
    1152             :      |                                         |
    1153             :      |                                         |
    1154             :      |                                         +--- query existing owner (return).
    1155             :      |
    1156             :      |
    1157             :      +--------name doesn't exist
    1158             :                         |
    1159             :                         |
    1160             :                         +--- add name (return).
    1161             : 
    1162             :  As can be seen from the above, the two cases may be collapsed onto each
    1163             :  other with the exception of the case where the name already exists and
    1164             :  is a group name. This case we handle with an if statement.
    1165             :  
    1166             : ************************************************************************/
    1167             : 
    1168           0 : void wins_process_name_registration_request(struct subnet_record *subrec,
    1169             :                                             struct packet_struct *p)
    1170             : {
    1171             :         unstring name;
    1172           0 :         struct nmb_packet *nmb = &p->packet.nmb;
    1173           0 :         struct nmb_name *question = &nmb->question.question_name;
    1174           0 :         bool bcast = nmb->header.nm_flags.bcast;
    1175           0 :         uint16_t nb_flags = get_nb_flags(nmb->additional->rdata);
    1176           0 :         int ttl = get_ttl_from_packet(nmb);
    1177           0 :         struct name_record *namerec = NULL;
    1178             :         struct in_addr from_ip;
    1179           0 :         bool registering_group_name = (nb_flags & NB_GROUP) ? True : False;
    1180             :         struct in_addr our_fake_ip;
    1181             : 
    1182           0 :         our_fake_ip = interpret_addr2("0.0.0.0");
    1183           0 :         putip((char *)&from_ip,&nmb->additional->rdata[2]);
    1184             : 
    1185           0 :         if(bcast) {
    1186             :                 /*
    1187             :                  * We should only get unicast name registration packets here.
    1188             :                  * Anyone trying to register broadcast should not be going to a WINS
    1189             :                  * server. Log an error here.
    1190             :                  */
    1191             : 
    1192           0 :                 DEBUG(0,("wins_process_name_registration_request: broadcast name registration request \
    1193             : received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
    1194             :                         nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
    1195           0 :                 return;
    1196             :         }
    1197             : 
    1198           0 :         DEBUG(3,("wins_process_name_registration_request: %s name registration for name %s \
    1199             : IP %s\n", registering_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) ));
    1200             : 
    1201             :         /*
    1202             :          * See if the name already exists.
    1203             :          */
    1204             : 
    1205           0 :         namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
    1206             : 
    1207             :         /*
    1208             :          * if the record exists but NOT in active state,
    1209             :          * consider it dead.
    1210             :          */
    1211           0 :         if ( (namerec != NULL) && !WINS_STATE_ACTIVE(namerec)) {
    1212           0 :                 DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was \
    1213             : not active - removing it.\n", nmb_namestr(question) ));
    1214           0 :                 remove_name_from_namelist( subrec, namerec );
    1215           0 :                 namerec = NULL;
    1216             :         }
    1217             : 
    1218             :         /*
    1219             :          * Deal with the case where the name found was a dns entry.
    1220             :          * Remove it as we now have a NetBIOS client registering the
    1221             :          * name.
    1222             :          */
    1223             : 
    1224           0 :         if( (namerec != NULL) && ( (namerec->data.source == DNS_NAME) || (namerec->data.source == DNSFAIL_NAME) ) ) {
    1225           0 :                 DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was \
    1226             : a dns lookup - removing it.\n", nmb_namestr(question) ));
    1227           0 :                 remove_name_from_namelist( subrec, namerec );
    1228           0 :                 namerec = NULL;
    1229             :         }
    1230             : 
    1231             :         /*
    1232             :          * Reject if the name exists and is not a REGISTER_NAME.
    1233             :          * (ie. Don't allow any static names to be overwritten.
    1234             :          */
    1235             : 
    1236           0 :         if((namerec != NULL) && (namerec->data.source != REGISTER_NAME)) {
    1237           0 :                 DEBUG( 3, ( "wins_process_name_registration_request: Attempt \
    1238             : to register name %s. Name already exists in WINS with source type %d.\n",
    1239             :                         nmb_namestr(question), namerec->data.source ));
    1240           0 :                 send_wins_name_registration_response(RFS_ERR, 0, p);
    1241           0 :                 return;
    1242             :         }
    1243             : 
    1244             :         /*
    1245             :          * Special policy decisions based on MS documentation.
    1246             :          * 1). All group names (except names ending in 0x1c) are added as 255.255.255.255.
    1247             :          * 2). All unique names ending in 0x1d are ignored, although a positive response is sent.
    1248             :          */
    1249             : 
    1250             :         /*
    1251             :          * A group name is always added as the local broadcast address, except
    1252             :          * for group names ending in 0x1c.
    1253             :          * Group names with type 0x1c are registered with individual IP addresses.
    1254             :          */
    1255             : 
    1256           0 :         if(registering_group_name && (question->name_type != 0x1c)) {
    1257           0 :                 from_ip = interpret_addr2("255.255.255.255");
    1258             :         }
    1259             : 
    1260             :         /*
    1261             :          * Ignore all attempts to register a unique 0x1d name, although return success.
    1262             :          */
    1263             : 
    1264           0 :         if(!registering_group_name && (question->name_type == 0x1d)) {
    1265           0 :                 DEBUG(3,("wins_process_name_registration_request: Ignoring request \
    1266             : to register name %s from IP %s.\n", nmb_namestr(question), inet_ntoa(p->ip) ));
    1267           0 :                 send_wins_name_registration_response(0, ttl, p);
    1268           0 :                 return;
    1269             :         }
    1270             : 
    1271             :         /*
    1272             :          * Next two cases are the 'if statement' mentioned above.
    1273             :          */
    1274             : 
    1275           0 :         if((namerec != NULL) && NAME_GROUP(namerec)) {
    1276           0 :                 if(registering_group_name) {
    1277             :                         /*
    1278             :                          * If we are adding a group name, the name exists and is also a group entry just add this
    1279             :                          * IP address to it and update the ttl.
    1280             :                          */
    1281             : 
    1282           0 :                         DEBUG(3,("wins_process_name_registration_request: Adding IP %s to group name %s.\n",
    1283             :                                 inet_ntoa(from_ip), nmb_namestr(question) ));
    1284             : 
    1285             :                         /* 
    1286             :                          * Check the ip address is not already in the group.
    1287             :                          */
    1288             : 
    1289           0 :                         if(!find_ip_in_name_record(namerec, from_ip)) {
    1290             :                                 /*
    1291             :                                  * Need to emulate the behaviour of Windows, as
    1292             :                                  * described in:
    1293             :                                  * http://lists.samba.org/archive/samba-technical/2001-October/016236.html
    1294             :                                  * (is there an MS reference for this
    1295             :                                  * somewhere?) because if the 1c list gets over
    1296             :                                  * 86 entries, the reply packet is too big
    1297             :                                  * (rdata>576 bytes) so no reply is sent.
    1298             :                                  *
    1299             :                                  * Keep only the "latest" 25 records, while
    1300             :                                  * ensuring that the PDC (0x1b) is never removed
    1301             :                                  * We do this by removing the first entry that
    1302             :                                  * isn't the 1b entry for the same name,
    1303             :                                  * on the grounds that insertion is at the end
    1304             :                                  * of the list, so the oldest entries are at
    1305             :                                  * the start.
    1306             :                                  *
    1307             :                                  */
    1308           0 :                                 while(namerec->data.num_ips>=25) {
    1309           0 :                                         struct name_record *name1brec = NULL;
    1310             : 
    1311             :                                         /* We only do this for 1c types. */
    1312           0 :                                         if (namerec->name.name_type != 0x1c) {
    1313           0 :                                                 break;
    1314             :                                         }
    1315           0 :                                         DEBUG(3,("wins_process_name_registration_request: "
    1316             :                                                 "More than 25 IPs already in "
    1317             :                                                 "the list. Looking for a 1b "
    1318             :                                                 "record\n"));
    1319             : 
    1320             :                                         /* Ensure we have all the active 1b
    1321             :                                          * names on the list. */
    1322           0 :                                         wins_delete_all_1b_in_memory_records();
    1323           0 :                                         fetch_all_active_wins_1b_names();
    1324             : 
    1325             :                                         /* Per the above, find the 1b record,
    1326             :                                            and then remove the first IP that isn't the same */
    1327           0 :                                         for(name1brec = subrec->namelist;
    1328           0 :                                                         name1brec;
    1329           0 :                                                         name1brec = name1brec->next ) {
    1330           0 :                                                 if( WINS_STATE_ACTIVE(name1brec) &&
    1331           0 :                                                                 name1brec->name.name_type == 0x1b) {
    1332           0 :                                                         DEBUG(3,("wins_process_name_registration_request: "
    1333             :                                                                 "Found the #1b record "
    1334             :                                                                 "with ip %s\n",
    1335             :                                                                 inet_ntoa(name1brec->data.ip[0])));
    1336           0 :                                                         break;
    1337             :                                                 }
    1338             :                                         }
    1339           0 :                                         if(!name1brec) {
    1340           0 :                                                 DEBUG(3,("wins_process_name_registration_request: "
    1341             :                                                         "Didn't find a #1b name record. "
    1342             :                                                         "Removing the first available "
    1343             :                                                         "entry %s\n",
    1344             :                                                         inet_ntoa(namerec->data.ip[0])));
    1345           0 :                                                 remove_ip_from_name_record(namerec, namerec->data.ip[0]);
    1346           0 :                                                 wins_hook("delete", namerec, 0);
    1347             :                                         } else {
    1348             :                                                 int i;
    1349           0 :                                                 for(i=0; i<namerec->data.num_ips; i++) {
    1350             :                                                         /* The name1brec should only have
    1351             :                                                          * the single IP address in it,
    1352             :                                                          * so we only check against the first one*/
    1353           0 :                                                         if(!ip_equal_v4( namerec->data.ip[i], name1brec->data.ip[0])) {
    1354             :                                                                 /* The i'th entry isn't the 1b address; delete it  */
    1355           0 :                                                                 DEBUG(3,("wins_process_name_registration_request: "
    1356             :                                                                         "Entry at %d is not the #1b address. "
    1357             :                                                                         "About to remove it\n",
    1358             :                                                                         i));
    1359           0 :                                                                 remove_ip_from_name_record(namerec, namerec->data.ip[i]);
    1360           0 :                                                                 wins_hook("delete", namerec, 0);
    1361           0 :                                                                 break;
    1362             :                                                         }
    1363             :                                                 }
    1364             :                                         }
    1365             :                                 }
    1366             :                                 /* The list is guaranteed to be < 25 entries now
    1367             :                                  * - safe to add a new one  */
    1368           0 :                                 add_ip_to_name_record(namerec, from_ip);
    1369             :                                 /* we need to update the record for replication */
    1370           0 :                                 get_global_id_and_update(&namerec->data.id, True);
    1371             : 
    1372             :                                 /*
    1373             :                                  * if the record is a replica, we must change
    1374             :                                  * the wins owner to us to make the replication updates
    1375             :                                  * it on the other wins servers.
    1376             :                                  * And when the partner will receive this record,
    1377             :                                  * it will update its own record.
    1378             :                                  */
    1379             : 
    1380           0 :                                 update_wins_owner(namerec, our_fake_ip);
    1381             :                         }
    1382           0 :                         update_name_ttl(namerec, ttl);
    1383           0 :                         wins_hook("refresh", namerec, ttl);
    1384           0 :                         send_wins_name_registration_response(0, ttl, p);
    1385           0 :                         return;
    1386             :                 } else {
    1387             : 
    1388             :                         /*
    1389             :                          * If we are adding a unique name, the name exists in the WINS db 
    1390             :                          * and is a group name then reject the registration.
    1391             :                          *
    1392             :                          * explanation: groups have a higher priority than unique names.
    1393             :                          */
    1394             : 
    1395           0 :                         DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
    1396             : already exists in WINS as a GROUP name.\n", nmb_namestr(question) ));
    1397           0 :                         send_wins_name_registration_response(RFS_ERR, 0, p);
    1398           0 :                         return;
    1399             :                 } 
    1400             :         }
    1401             : 
    1402             :         /*
    1403             :          * From here on down we know that if the name exists in the WINS db it is
    1404             :          * a unique name, not a group name.
    1405             :          */
    1406             : 
    1407             :         /* 
    1408             :          * If the name exists and is one of our names then check the
    1409             :          * registering IP address. If it's not one of ours then automatically
    1410             :          * reject without doing the query - we know we will reject it.
    1411             :          */
    1412             : 
    1413           0 :         if ( namerec != NULL ) {
    1414           0 :                 pull_ascii_nstring(name, sizeof(name), namerec->name.name);
    1415           0 :                 if( is_myname(name) ) {
    1416           0 :                         if(!ismyip_v4(from_ip)) {
    1417           0 :                                 DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
    1418             : is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
    1419           0 :                                 send_wins_name_registration_response(RFS_ERR, 0, p);
    1420           0 :                                 return;
    1421             :                         } else {
    1422             :                                 /*
    1423             :                                  * It's one of our names and one of our IP's - update the ttl.
    1424             :                                  */
    1425           0 :                                 update_name_ttl(namerec, ttl);
    1426           0 :                                 wins_hook("refresh", namerec, ttl);
    1427           0 :                                 send_wins_name_registration_response(0, ttl, p);
    1428           0 :                                 return;
    1429             :                         }
    1430             :                 }
    1431             :         } else {
    1432           0 :                 name[0] = '\0';
    1433             :         }
    1434             : 
    1435             :         /*
    1436             :          * If the name exists and it is a unique registration and the registering IP 
    1437             :          * is the same as the (single) already registered IP then just update the ttl.
    1438             :          *
    1439             :          * But not if the record is an active replica. IF it's a replica, it means it can be
    1440             :          * the same client which has moved and not yet expired. So we don't update
    1441             :          * the ttl in this case and go beyond to do a WACK and query the old client
    1442             :          */
    1443             : 
    1444           0 :         if( !registering_group_name
    1445           0 :                         && (namerec != NULL)
    1446           0 :                         && (namerec->data.num_ips == 1)
    1447           0 :                         && ip_equal_v4( namerec->data.ip[0], from_ip )
    1448           0 :                         && ip_equal_v4(namerec->data.wins_ip, our_fake_ip) ) {
    1449           0 :                 update_name_ttl( namerec, ttl );
    1450           0 :                 wins_hook("refresh", namerec, ttl);
    1451           0 :                 send_wins_name_registration_response( 0, ttl, p );
    1452           0 :                 return;
    1453             :         }
    1454             : 
    1455             :         /*
    1456             :          * Finally if the name exists do a query to the registering machine 
    1457             :          * to see if they still claim to have the name.
    1458             :          */
    1459             : 
    1460           0 :         if( namerec != NULL ) {
    1461             :                 long *ud[(sizeof(struct userdata_struct) + sizeof(struct packet_struct *))/sizeof(long *) + 1];
    1462           0 :                 struct userdata_struct *userdata = (struct userdata_struct *)ud;
    1463             : 
    1464             :                 /*
    1465             :                  * First send a WACK to the registering machine.
    1466             :                  */
    1467             : 
    1468           0 :                 send_wins_wack_response(60, p);
    1469             : 
    1470             :                 /*
    1471             :                  * When the reply comes back we need the original packet.
    1472             :                  * Lock this so it won't be freed and then put it into
    1473             :                  * the userdata structure.
    1474             :                  */
    1475             : 
    1476           0 :                 p->locked = True;
    1477             : 
    1478           0 :                 userdata = (struct userdata_struct *)ud;
    1479             : 
    1480           0 :                 userdata->copy_fn = NULL;
    1481           0 :                 userdata->free_fn = NULL;
    1482           0 :                 userdata->userdata_len = sizeof(struct packet_struct *);
    1483           0 :                 memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
    1484             : 
    1485             :                 /*
    1486             :                  * Use the new call to send a query directly to an IP address.
    1487             :                  * This sends the query directly to the IP address, and ensures
    1488             :                  * the recursion desired flag is not set (you were right Luke :-).
    1489             :                  * This function should *only* be called from the WINS server
    1490             :                  * code. JRA.
    1491             :                  */
    1492             : 
    1493           0 :                 pull_ascii_nstring(name, sizeof(name), question->name);
    1494           0 :                 query_name_from_wins_server( *namerec->data.ip,
    1495             :                                 name,
    1496           0 :                                 question->name_type, 
    1497             :                                 wins_register_query_success,
    1498             :                                 wins_register_query_fail,
    1499             :                                 userdata );
    1500           0 :                 return;
    1501             :         }
    1502             : 
    1503             :         /*
    1504             :          * Name did not exist - add it.
    1505             :          */
    1506             : 
    1507           0 :         pull_ascii_nstring(name, sizeof(name), question->name);
    1508           0 :         add_name_to_subnet( subrec, name, question->name_type,
    1509             :                         nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
    1510             : 
    1511           0 :         if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) {
    1512           0 :                 get_global_id_and_update(&namerec->data.id, True);
    1513           0 :                 update_wins_owner(namerec, our_fake_ip);
    1514           0 :                 update_wins_flag(namerec, WINS_ACTIVE);
    1515           0 :                 wins_hook("add", namerec, ttl);
    1516             :         }
    1517             : 
    1518           0 :         send_wins_name_registration_response(0, ttl, p);
    1519             : }
    1520             : 
    1521             : /***********************************************************************
    1522             :  Deal with a mutihomed name query success to the machine that
    1523             :  requested the multihomed name registration.
    1524             : 
    1525             :  We have a locked pointer to the original packet stashed away in the
    1526             :  userdata pointer.
    1527             : ************************************************************************/
    1528             : 
    1529           0 : static void wins_multihomed_register_query_success(struct subnet_record *subrec,
    1530             :                                              struct userdata_struct *userdata,
    1531             :                                              struct nmb_name *question_name,
    1532             :                                              struct in_addr ip,
    1533             :                                              struct res_rec *answers)
    1534             : {
    1535             :         struct packet_struct *orig_reg_packet;
    1536             :         struct nmb_packet *nmb;
    1537           0 :         struct name_record *namerec = NULL;
    1538             :         struct in_addr from_ip;
    1539             :         int ttl;
    1540             :         struct in_addr our_fake_ip;
    1541             : 
    1542           0 :         our_fake_ip = interpret_addr2("0.0.0.0");
    1543           0 :         memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
    1544             : 
    1545           0 :         nmb = &orig_reg_packet->packet.nmb;
    1546             : 
    1547           0 :         putip((char *)&from_ip,&nmb->additional->rdata[2]);
    1548           0 :         ttl = get_ttl_from_packet(nmb);
    1549             : 
    1550             :         /*
    1551             :          * We want to just add the new IP, as we now know the requesting
    1552             :          * machine claims to own it. But we can't just do that as an arbitrary
    1553             :          * amount of time may have taken place between the name query
    1554             :          * request and this response. So we check that
    1555             :          * the name still exists and is in the same state - if so
    1556             :          * we just add the extra IP and update the ttl.
    1557             :          */
    1558             : 
    1559           0 :         namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
    1560             : 
    1561           0 :         if( (namerec == NULL) || (namerec->data.source != REGISTER_NAME) || !WINS_STATE_ACTIVE(namerec) ) {
    1562           0 :                 DEBUG(3,("wins_multihomed_register_query_success: name %s is not in the correct state to add \
    1563             : a subsequent IP address.\n", nmb_namestr(question_name) ));
    1564           0 :                 send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
    1565             : 
    1566           0 :                 orig_reg_packet->locked = False;
    1567           0 :                 free_packet(orig_reg_packet);
    1568             : 
    1569           0 :                 return;
    1570             :         }
    1571             : 
    1572           0 :         if(!find_ip_in_name_record(namerec, from_ip)) {
    1573           0 :                 add_ip_to_name_record(namerec, from_ip);
    1574             :         }
    1575             : 
    1576           0 :         get_global_id_and_update(&namerec->data.id, True);
    1577           0 :         update_wins_owner(namerec, our_fake_ip);
    1578           0 :         update_wins_flag(namerec, WINS_ACTIVE);
    1579           0 :         update_name_ttl(namerec, ttl);
    1580           0 :         wins_hook("add", namerec, ttl);
    1581           0 :         send_wins_name_registration_response(0, ttl, orig_reg_packet);
    1582             : 
    1583           0 :         orig_reg_packet->locked = False;
    1584           0 :         free_packet(orig_reg_packet);
    1585             : }
    1586             : 
    1587             : /***********************************************************************
    1588             :  Deal with a name registration request query failure to a client that
    1589             :  owned the name.
    1590             : 
    1591             :  We have a locked pointer to the original packet stashed away in the
    1592             :  userdata pointer.
    1593             : ************************************************************************/
    1594             : 
    1595           0 : static void wins_multihomed_register_query_fail(struct subnet_record *subrec,
    1596             :                                           struct response_record *rrec,
    1597             :                                           struct nmb_name *question_name,
    1598             :                                           int rcode)
    1599             : {
    1600           0 :         struct userdata_struct *userdata = rrec->userdata;
    1601             :         struct packet_struct *orig_reg_packet;
    1602             : 
    1603           0 :         memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
    1604             : 
    1605           0 :         DEBUG(3,("wins_multihomed_register_query_fail: Registering machine at IP %s failed to answer \
    1606             : query successfully for name %s.\n", inet_ntoa(orig_reg_packet->ip), nmb_namestr(question_name) ));
    1607           0 :         send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
    1608             : 
    1609           0 :         orig_reg_packet->locked = False;
    1610           0 :         free_packet(orig_reg_packet);
    1611           0 :         return;
    1612             : }
    1613             : 
    1614             : /***********************************************************************
    1615             :  Deal with a multihomed name registration request to a WINS server.
    1616             :  These cannot be group name registrations.
    1617             : ***********************************************************************/
    1618             : 
    1619           0 : void wins_process_multihomed_name_registration_request( struct subnet_record *subrec,
    1620             :                                                         struct packet_struct *p)
    1621             : {
    1622           0 :         struct nmb_packet *nmb = &p->packet.nmb;
    1623           0 :         struct nmb_name *question = &nmb->question.question_name;
    1624           0 :         bool bcast = nmb->header.nm_flags.bcast;
    1625           0 :         uint16_t nb_flags = get_nb_flags(nmb->additional->rdata);
    1626           0 :         int ttl = get_ttl_from_packet(nmb);
    1627           0 :         struct name_record *namerec = NULL;
    1628             :         struct in_addr from_ip;
    1629           0 :         bool group = (nb_flags & NB_GROUP) ? True : False;
    1630             :         struct in_addr our_fake_ip;
    1631             :         unstring qname;
    1632             : 
    1633           0 :         our_fake_ip = interpret_addr2("0.0.0.0");
    1634           0 :         putip((char *)&from_ip,&nmb->additional->rdata[2]);
    1635             : 
    1636           0 :         if(bcast) {
    1637             :                 /*
    1638             :                  * We should only get unicast name registration packets here.
    1639             :                  * Anyone trying to register broadcast should not be going to a WINS
    1640             :                  * server. Log an error here.
    1641             :                  */
    1642             : 
    1643           0 :                 DEBUG(0,("wins_process_multihomed_name_registration_request: broadcast name registration request \
    1644             : received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
    1645             :                         nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
    1646           0 :                 return;
    1647             :         }
    1648             : 
    1649             :         /*
    1650             :          * Only unique names should be registered multihomed.
    1651             :          */
    1652             : 
    1653           0 :         if(group) {
    1654           0 :                 DEBUG(0,("wins_process_multihomed_name_registration_request: group name registration request \
    1655             : received for name %s from IP %s on subnet %s. Error - group names should not be multihomed.\n",
    1656             :                         nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
    1657           0 :                 return;
    1658             :         }
    1659             : 
    1660           0 :         DEBUG(3,("wins_process_multihomed_name_registration_request: name registration for name %s \
    1661             : IP %s\n", nmb_namestr(question), inet_ntoa(from_ip) ));
    1662             : 
    1663             :         /*
    1664             :          * Deal with policy regarding 0x1d names.
    1665             :          */
    1666             : 
    1667           0 :         if(question->name_type == 0x1d) {
    1668           0 :                 DEBUG(3,("wins_process_multihomed_name_registration_request: Ignoring request \
    1669             : to register name %s from IP %s.\n", nmb_namestr(question), inet_ntoa(p->ip) ));
    1670           0 :                 send_wins_name_registration_response(0, ttl, p);  
    1671           0 :                 return;
    1672             :         }
    1673             : 
    1674             :         /*
    1675             :          * See if the name already exists.
    1676             :          */
    1677             : 
    1678           0 :         namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
    1679             : 
    1680             :         /*
    1681             :          * if the record exists but NOT in active state,
    1682             :          * consider it dead.
    1683             :          */
    1684             : 
    1685           0 :         if ((namerec != NULL) && !WINS_STATE_ACTIVE(namerec)) {
    1686           0 :                 DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was not active - removing it.\n", nmb_namestr(question)));
    1687           0 :                 remove_name_from_namelist(subrec, namerec);
    1688           0 :                 namerec = NULL;
    1689             :         }
    1690             : 
    1691             :         /*
    1692             :          * Deal with the case where the name found was a dns entry.
    1693             :          * Remove it as we now have a NetBIOS client registering the
    1694             :          * name.
    1695             :          */
    1696             : 
    1697           0 :         if( (namerec != NULL) && ( (namerec->data.source == DNS_NAME) || (namerec->data.source == DNSFAIL_NAME) ) ) {
    1698           0 :                 DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was a dns lookup \
    1699             : - removing it.\n", nmb_namestr(question) ));
    1700           0 :                 remove_name_from_namelist( subrec, namerec);
    1701           0 :                 namerec = NULL;
    1702             :         }
    1703             : 
    1704             :         /*
    1705             :          * Reject if the name exists and is not a REGISTER_NAME.
    1706             :          * (ie. Don't allow any static names to be overwritten.
    1707             :          */
    1708             : 
    1709           0 :         if( (namerec != NULL) && (namerec->data.source != REGISTER_NAME) ) {
    1710           0 :                 DEBUG( 3, ( "wins_process_multihomed_name_registration_request: Attempt \
    1711             : to register name %s. Name already exists in WINS with source type %d.\n",
    1712             :                         nmb_namestr(question), namerec->data.source ));
    1713           0 :                 send_wins_name_registration_response(RFS_ERR, 0, p);
    1714           0 :                 return;
    1715             :         }
    1716             : 
    1717             :         /*
    1718             :          * Reject if the name exists and is a GROUP name and is active.
    1719             :          */
    1720             : 
    1721           0 :         if((namerec != NULL) && NAME_GROUP(namerec) && WINS_STATE_ACTIVE(namerec)) {
    1722           0 :                 DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
    1723             : already exists in WINS as a GROUP name.\n", nmb_namestr(question) ));
    1724           0 :                 send_wins_name_registration_response(RFS_ERR, 0, p);
    1725           0 :                 return;
    1726             :         } 
    1727             : 
    1728             :         /*
    1729             :          * From here on down we know that if the name exists in the WINS db it is
    1730             :          * a unique name, not a group name.
    1731             :          */
    1732             : 
    1733             :         /*
    1734             :          * If the name exists and is one of our names then check the
    1735             :          * registering IP address. If it's not one of ours then automatically
    1736             :          * reject without doing the query - we know we will reject it.
    1737             :          */
    1738             : 
    1739           0 :         if((namerec != NULL) && (is_myname(namerec->name.name)) ) {
    1740           0 :                 if(!ismyip_v4(from_ip)) {
    1741           0 :                         DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
    1742             : is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
    1743           0 :                         send_wins_name_registration_response(RFS_ERR, 0, p);
    1744           0 :                         return;
    1745             :                 } else {
    1746             :                         /*
    1747             :                          * It's one of our names and one of our IP's. Ensure the IP is in the record and
    1748             :                          *  update the ttl. Update the version ID to force replication.
    1749             :                          */
    1750           0 :                         update_name_ttl(namerec, ttl);
    1751             : 
    1752           0 :                         if(!find_ip_in_name_record(namerec, from_ip)) {
    1753           0 :                                 get_global_id_and_update(&namerec->data.id, True);
    1754           0 :                                 update_wins_owner(namerec, our_fake_ip);
    1755           0 :                                 update_wins_flag(namerec, WINS_ACTIVE);
    1756             : 
    1757           0 :                                 add_ip_to_name_record(namerec, from_ip);
    1758             :                         }
    1759             : 
    1760           0 :                         wins_hook("refresh", namerec, ttl);
    1761           0 :                         send_wins_name_registration_response(0, ttl, p);
    1762           0 :                         return;
    1763             :                 }
    1764             :         }
    1765             : 
    1766             :         /*
    1767             :          * If the name exists and is active, check if the IP address is already registered
    1768             :          * to that name. If so then update the ttl and reply success.
    1769             :          */
    1770             : 
    1771           0 :         if((namerec != NULL) && find_ip_in_name_record(namerec, from_ip) && WINS_STATE_ACTIVE(namerec)) {
    1772           0 :                 update_name_ttl(namerec, ttl);
    1773             : 
    1774             :                 /*
    1775             :                  * If it's a replica, we need to become the wins owner
    1776             :                  * to force the replication
    1777             :                  */
    1778           0 :                 if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
    1779           0 :                         get_global_id_and_update(&namerec->data.id, True);
    1780           0 :                         update_wins_owner(namerec, our_fake_ip);
    1781           0 :                         update_wins_flag(namerec, WINS_ACTIVE);
    1782             :                 }
    1783             : 
    1784           0 :                 wins_hook("refresh", namerec, ttl);
    1785           0 :                 send_wins_name_registration_response(0, ttl, p);
    1786           0 :                 return;
    1787             :         }
    1788             : 
    1789             :         /*
    1790             :          * If the name exists do a query to the owner
    1791             :          * to see if they still want the name.
    1792             :          */
    1793             : 
    1794           0 :         if(namerec != NULL) {
    1795             :                 long *ud[(sizeof(struct userdata_struct) + sizeof(struct packet_struct *))/sizeof(long *) + 1];
    1796           0 :                 struct userdata_struct *userdata = (struct userdata_struct *)ud;
    1797             : 
    1798             :                 /*
    1799             :                  * First send a WACK to the registering machine.
    1800             :                  */
    1801             : 
    1802           0 :                 send_wins_wack_response(60, p);
    1803             : 
    1804             :                 /*
    1805             :                  * When the reply comes back we need the original packet.
    1806             :                  * Lock this so it won't be freed and then put it into
    1807             :                  * the userdata structure.
    1808             :                  */
    1809             : 
    1810           0 :                 p->locked = True;
    1811             : 
    1812           0 :                 userdata = (struct userdata_struct *)ud;
    1813             : 
    1814           0 :                 userdata->copy_fn = NULL;
    1815           0 :                 userdata->free_fn = NULL;
    1816           0 :                 userdata->userdata_len = sizeof(struct packet_struct *);
    1817           0 :                 memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
    1818             : 
    1819             :                 /* 
    1820             :                  * Use the new call to send a query directly to an IP address.
    1821             :                  * This sends the query directly to the IP address, and ensures
    1822             :                  * the recursion desired flag is not set (you were right Luke :-).
    1823             :                  * This function should *only* be called from the WINS server
    1824             :                  * code. JRA.
    1825             :                  *
    1826             :                  * Note that this packet is sent to the current owner of the name,
    1827             :                  * not the person who sent the packet 
    1828             :                  */
    1829             : 
    1830           0 :                 pull_ascii_nstring( qname, sizeof(qname), question->name);
    1831           0 :                 query_name_from_wins_server( namerec->data.ip[0],
    1832             :                                 qname,
    1833           0 :                                 question->name_type, 
    1834             :                                 wins_multihomed_register_query_success,
    1835             :                                 wins_multihomed_register_query_fail,
    1836             :                                 userdata );
    1837             : 
    1838           0 :                 return;
    1839             :         }
    1840             : 
    1841             :         /*
    1842             :          * Name did not exist - add it.
    1843             :          */
    1844             : 
    1845           0 :         pull_ascii_nstring( qname, sizeof(qname), question->name);
    1846           0 :         add_name_to_subnet( subrec, qname, question->name_type,
    1847             :                         nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
    1848             : 
    1849           0 :         if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) {
    1850           0 :                 get_global_id_and_update(&namerec->data.id, True);
    1851           0 :                 update_wins_owner(namerec, our_fake_ip);
    1852           0 :                 update_wins_flag(namerec, WINS_ACTIVE);
    1853           0 :                 wins_hook("add", namerec, ttl);
    1854             :         }
    1855             : 
    1856           0 :         send_wins_name_registration_response(0, ttl, p);
    1857             : }
    1858             : 
    1859             : /***********************************************************************
    1860             :  Fetch all *<1b> names from the WINS db and store on the namelist.
    1861             : ***********************************************************************/
    1862             : 
    1863           0 : static int fetch_1b_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
    1864             : {
    1865           0 :         struct name_record *namerec = NULL;
    1866             : 
    1867           0 :         if (kbuf.dsize != sizeof(unstring) + 1) {
    1868           0 :                 return 0;
    1869             :         }
    1870             : 
    1871             :         /* Filter out all non-1b names. */
    1872           0 :         if (kbuf.dptr[sizeof(unstring)] != 0x1b) {
    1873           0 :                 return 0;
    1874             :         }
    1875             : 
    1876           0 :         namerec = wins_record_to_name_record(kbuf, dbuf);
    1877           0 :         if (!namerec) {
    1878           0 :                 return 0;
    1879             :         }
    1880             : 
    1881           0 :         DLIST_ADD(wins_server_subnet->namelist, namerec);
    1882           0 :         return 0;
    1883             : }
    1884             : 
    1885           0 : void fetch_all_active_wins_1b_names(void)
    1886             : {
    1887           0 :         tdb_traverse(wins_tdb, fetch_1b_traverse_fn, NULL);
    1888           0 : }
    1889             : 
    1890             : /***********************************************************************
    1891             :  Deal with the special name query for *<1b>.
    1892             : ***********************************************************************/
    1893             : 
    1894           0 : static void process_wins_dmb_query_request(struct subnet_record *subrec,
    1895             :                                            struct packet_struct *p)
    1896             : {
    1897           0 :         struct name_record *namerec = NULL;
    1898             :         char *prdata;
    1899             :         int num_ips;
    1900             : 
    1901             :         /*
    1902             :          * Go through all the ACTIVE names in the WINS db looking for those
    1903             :          * ending in <1b>. Use this to calculate the number of IP
    1904             :          * addresses we need to return.
    1905             :          */
    1906             : 
    1907           0 :         num_ips = 0;
    1908             : 
    1909             :         /* First, clear the in memory list - we're going to re-populate
    1910             :            it with the tdb_traversal in fetch_all_active_wins_1b_names. */
    1911             : 
    1912           0 :         wins_delete_all_tmp_in_memory_records();
    1913             : 
    1914           0 :         fetch_all_active_wins_1b_names();
    1915             : 
    1916           0 :         for( namerec = subrec->namelist; namerec; namerec = namerec->next ) {
    1917           0 :                 if( WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) {
    1918           0 :                         num_ips += namerec->data.num_ips;
    1919             :                 }
    1920             :         }
    1921             : 
    1922           0 :         if(num_ips == 0) {
    1923             :                 /*
    1924             :                  * There are no 0x1b names registered. Return name query fail.
    1925             :                  */
    1926           0 :                 send_wins_name_query_response(NAM_ERR, p, NULL);
    1927           0 :                 return;
    1928             :         }
    1929             : 
    1930           0 :         if((prdata = (char *)SMB_MALLOC( num_ips * 6 )) == NULL) {
    1931           0 :                 DEBUG(0,("process_wins_dmb_query_request: Malloc fail !.\n"));
    1932           0 :                 return;
    1933             :         }
    1934             : 
    1935             :         /*
    1936             :          * Go through all the names again in the WINS db looking for those
    1937             :          * ending in <1b>. Add their IP addresses into the list we will
    1938             :          * return.
    1939             :          */ 
    1940             : 
    1941           0 :         num_ips = 0;
    1942           0 :         for( namerec = subrec->namelist; namerec; namerec = namerec->next ) {
    1943           0 :                 if( WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) {
    1944             :                         int i;
    1945           0 :                         for(i = 0; i < namerec->data.num_ips; i++) {
    1946           0 :                                 set_nb_flags(&prdata[num_ips * 6],namerec->data.nb_flags);
    1947           0 :                                 putip((char *)&prdata[(num_ips * 6) + 2], &namerec->data.ip[i]);
    1948           0 :                                 num_ips++;
    1949             :                         }
    1950             :                 }
    1951             :         }
    1952             : 
    1953             :         /*
    1954             :          * Send back the reply containing the IP list.
    1955             :          */
    1956             : 
    1957           0 :         reply_netbios_packet(p,                                /* Packet to reply to. */
    1958             :                                 0,                             /* Result code. */
    1959             :                                 WINS_QUERY,                    /* nmbd type code. */
    1960             :                                 NMB_NAME_QUERY_OPCODE,         /* opcode. */
    1961             :                                 lp_min_wins_ttl(),             /* ttl. */
    1962             :                                 prdata,                        /* data to send. */
    1963             :                                 num_ips*6);                    /* data length. */
    1964             : 
    1965           0 :         SAFE_FREE(prdata);
    1966             : }
    1967             : 
    1968             : /****************************************************************************
    1969             : Send a WINS name query response.
    1970             : **************************************************************************/
    1971             : 
    1972           0 : void send_wins_name_query_response(int rcode, struct packet_struct *p, 
    1973             :                                           struct name_record *namerec)
    1974             : {
    1975             :         char rdata[6];
    1976           0 :         char *prdata = rdata;
    1977           0 :         int reply_data_len = 0;
    1978           0 :         int ttl = 0;
    1979             :         int i;
    1980             : 
    1981           0 :         memset(rdata,'\0',6);
    1982             : 
    1983           0 :         if(rcode == 0) {
    1984             : 
    1985             :                 int ip_count;
    1986             : 
    1987           0 :                 ttl = (namerec->data.death_time != PERMANENT_TTL) ?  namerec->data.death_time - p->timestamp : lp_max_wins_ttl();
    1988             : 
    1989             :                 /* The netbios reply packet data section is limited to 576 bytes.  In theory 
    1990             :                  * this should give us space for 96 addresses, but in practice, 86 appears 
    1991             :                  * to be the max (don't know why).  If we send any more than that, 
    1992             :                  * reply_netbios_packet will fail to send a reply to avoid a memcpy buffer 
    1993             :                  * overflow.  Keep the count to 85 and it will be ok */
    1994           0 :                 ip_count=namerec->data.num_ips;
    1995           0 :                 if(ip_count>85) {
    1996           0 :                         ip_count=85;    
    1997             :                 }
    1998             : 
    1999             :                 /* Copy all known ip addresses into the return data. */
    2000             :                 /* Optimise for the common case of one IP address so we don't need a malloc. */
    2001             : 
    2002           0 :                 if( ip_count == 1 ) {
    2003           0 :                         prdata = rdata;
    2004             :                 } else {
    2005           0 :                         if((prdata = (char *)SMB_MALLOC( ip_count * 6 )) == NULL) {
    2006           0 :                                 DEBUG(0,("send_wins_name_query_response: malloc fail !\n"));
    2007           0 :                                 return;
    2008             :                         }
    2009             :                 }
    2010             : 
    2011           0 :                 for(i = 0; i < ip_count; i++) {
    2012           0 :                         set_nb_flags(&prdata[i*6],namerec->data.nb_flags);
    2013           0 :                         putip((char *)&prdata[2+(i*6)], &namerec->data.ip[i]);
    2014             :                 }
    2015             : 
    2016           0 :                 sort_query_replies(prdata, i, p->ip);
    2017           0 :                 reply_data_len = ip_count * 6;
    2018             :         }
    2019             : 
    2020           0 :         reply_netbios_packet(p,                                /* Packet to reply to. */
    2021             :                                 rcode,                         /* Result code. */
    2022             :                                 WINS_QUERY,                    /* nmbd type code. */
    2023             :                                 NMB_NAME_QUERY_OPCODE,         /* opcode. */
    2024             :                                 ttl,                           /* ttl. */
    2025             :                                 prdata,                        /* data to send. */
    2026             :                                 reply_data_len);               /* data length. */
    2027             : 
    2028           0 :         if(prdata != rdata) {
    2029           0 :                 SAFE_FREE(prdata);
    2030             :         }
    2031             : }
    2032             : 
    2033             : /***********************************************************************
    2034             :  Deal with a name query.
    2035             : ***********************************************************************/
    2036             : 
    2037           0 : void wins_process_name_query_request(struct subnet_record *subrec, 
    2038             :                                      struct packet_struct *p)
    2039             : {
    2040           0 :         struct nmb_packet *nmb = &p->packet.nmb;
    2041           0 :         struct nmb_name *question = &nmb->question.question_name;
    2042           0 :         struct name_record *namerec = NULL;
    2043             :         unstring qname;
    2044             : 
    2045           0 :         DEBUG(3,("wins_process_name_query: name query for name %s from IP %s\n", 
    2046             :                 nmb_namestr(question), inet_ntoa(p->ip) ));
    2047             : 
    2048             :         /*
    2049             :          * Special name code. If the queried name is *<1b> then search
    2050             :          * the entire WINS database and return a list of all the IP addresses
    2051             :          * registered to any <1b> name. This is to allow domain master browsers
    2052             :          * to discover other domains that may not have a presence on their subnet.
    2053             :          */
    2054             : 
    2055           0 :         pull_ascii_nstring(qname, sizeof(qname), question->name);
    2056           0 :         if(strequal( qname, "*") && (question->name_type == 0x1b)) {
    2057           0 :                 process_wins_dmb_query_request( subrec, p);
    2058           0 :                 return;
    2059             :         }
    2060             : 
    2061           0 :         namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
    2062             : 
    2063           0 :         if(namerec != NULL) {
    2064             :                 /*
    2065             :                  * If the name is not anymore in active state then reply not found.
    2066             :                  * it's fair even if we keep it in the cache for days.
    2067             :                  */
    2068           0 :                 if (!WINS_STATE_ACTIVE(namerec)) {
    2069           0 :                         DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n",
    2070             :                                 nmb_namestr(question) ));
    2071           0 :                         send_wins_name_query_response(NAM_ERR, p, namerec);
    2072           0 :                         return;
    2073             :                 }
    2074             : 
    2075             :                 /* 
    2076             :                  * If it's a DNSFAIL_NAME then reply name not found.
    2077             :                  */
    2078             : 
    2079           0 :                 if( namerec->data.source == DNSFAIL_NAME ) {
    2080           0 :                         DEBUG(3,("wins_process_name_query: name query for name %s returning DNS fail.\n",
    2081             :                                 nmb_namestr(question) ));
    2082           0 :                         send_wins_name_query_response(NAM_ERR, p, namerec);
    2083           0 :                         return;
    2084             :                 }
    2085             : 
    2086             :                 /*
    2087             :                  * If the name has expired then reply name not found.
    2088             :                  */
    2089             : 
    2090           0 :                 if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < p->timestamp) ) {
    2091           0 :                         DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n",
    2092             :                                         nmb_namestr(question) ));
    2093           0 :                         send_wins_name_query_response(NAM_ERR, p, namerec);
    2094           0 :                         return;
    2095             :                 }
    2096             : 
    2097           0 :                 DEBUG(3,("wins_process_name_query: name query for name %s returning first IP %s.\n",
    2098             :                                 nmb_namestr(question), inet_ntoa(namerec->data.ip[0]) ));
    2099             : 
    2100           0 :                 send_wins_name_query_response(0, p, namerec);
    2101           0 :                 return;
    2102             :         }
    2103             : 
    2104             :         /* 
    2105             :          * Name not found in WINS - try a dns query if it's a 0x20 name.
    2106             :          */
    2107             : 
    2108           0 :         if(lp_wins_dns_proxy() && ((question->name_type == 0x20) || question->name_type == 0)) {
    2109           0 :                 DEBUG(3,("wins_process_name_query: name query for name %s not found - doing dns lookup.\n",
    2110             :                                 nmb_namestr(question) ));
    2111             : 
    2112           0 :                 queue_dns_query(p, question);
    2113           0 :                 return;
    2114             :         }
    2115             : 
    2116             :         /*
    2117             :          * Name not found - return error.
    2118             :          */
    2119             : 
    2120           0 :         send_wins_name_query_response(NAM_ERR, p, NULL);
    2121             : }
    2122             : 
    2123             : /****************************************************************************
    2124             : Send a WINS name release response.
    2125             : **************************************************************************/
    2126             : 
    2127           0 : static void send_wins_name_release_response(int rcode, struct packet_struct *p)
    2128             : {
    2129           0 :         struct nmb_packet *nmb = &p->packet.nmb;
    2130             :         char rdata[6];
    2131             : 
    2132           0 :         memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
    2133             : 
    2134           0 :         reply_netbios_packet(p,                               /* Packet to reply to. */
    2135             :                                 rcode,                        /* Result code. */
    2136             :                                 NMB_REL,                      /* nmbd type code. */
    2137             :                                 NMB_NAME_RELEASE_OPCODE,      /* opcode. */
    2138             :                                 0,                            /* ttl. */
    2139             :                                 rdata,                        /* data to send. */
    2140             :                                 6);                           /* data length. */
    2141           0 : }
    2142             : 
    2143             : /***********************************************************************
    2144             :  Deal with a name release.
    2145             : ***********************************************************************/
    2146             : 
    2147           0 : void wins_process_name_release_request(struct subnet_record *subrec,
    2148             :                                        struct packet_struct *p)
    2149             : {
    2150           0 :         struct nmb_packet *nmb = &p->packet.nmb;
    2151           0 :         struct nmb_name *question = &nmb->question.question_name;
    2152           0 :         bool bcast = nmb->header.nm_flags.bcast;
    2153           0 :         uint16_t nb_flags = get_nb_flags(nmb->additional->rdata);
    2154           0 :         struct name_record *namerec = NULL;
    2155             :         struct in_addr from_ip;
    2156           0 :         bool releasing_group_name = (nb_flags & NB_GROUP) ? True : False;
    2157             : 
    2158           0 :         putip((char *)&from_ip,&nmb->additional->rdata[2]);
    2159             : 
    2160           0 :         if(bcast) {
    2161             :                 /*
    2162             :                  * We should only get unicast name registration packets here.
    2163             :                  * Anyone trying to register broadcast should not be going to a WINS
    2164             :                  * server. Log an error here.
    2165             :                  */
    2166             : 
    2167           0 :                 DEBUG(0,("wins_process_name_release_request: broadcast name registration request \
    2168             : received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
    2169             :                         nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
    2170           0 :                 return;
    2171             :         }
    2172             : 
    2173           0 :         DEBUG(3,("wins_process_name_release_request: %s name release for name %s \
    2174             : IP %s\n", releasing_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) ));
    2175             : 
    2176             :         /*
    2177             :          * Deal with policy regarding 0x1d names.
    2178             :          */
    2179             : 
    2180           0 :         if(!releasing_group_name && (question->name_type == 0x1d)) {
    2181           0 :                 DEBUG(3,("wins_process_name_release_request: Ignoring request \
    2182             : to release name %s from IP %s.\n", nmb_namestr(question), inet_ntoa(p->ip) ));
    2183           0 :                 send_wins_name_release_response(0, p);
    2184           0 :                 return;
    2185             :         }
    2186             : 
    2187             :         /*
    2188             :          * See if the name already exists.
    2189             :          */
    2190             : 
    2191           0 :         namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
    2192             : 
    2193           0 :         if( (namerec == NULL) || ((namerec != NULL) && (namerec->data.source != REGISTER_NAME)) ) {
    2194           0 :                 send_wins_name_release_response(NAM_ERR, p);
    2195           0 :                 return;
    2196             :         }
    2197             : 
    2198             :         /* 
    2199             :          * Check that the sending machine has permission to release this name.
    2200             :          * If it's a group name not ending in 0x1c then just say yes and let
    2201             :          * the group time out.
    2202             :          */
    2203             : 
    2204           0 :         if(releasing_group_name && (question->name_type != 0x1c)) {
    2205           0 :                 send_wins_name_release_response(0, p);
    2206           0 :                 return;
    2207             :         }
    2208             : 
    2209             :         /* 
    2210             :          * Check that the releasing node is on the list of IP addresses
    2211             :          * for this name. Disallow the release if not.
    2212             :          */
    2213             : 
    2214           0 :         if(!find_ip_in_name_record(namerec, from_ip)) {
    2215           0 :                 DEBUG(3,("wins_process_name_release_request: Refusing request to \
    2216             : release name %s as IP %s is not one of the known IP's for this name.\n",
    2217             :                         nmb_namestr(question), inet_ntoa(from_ip) ));
    2218           0 :                 send_wins_name_release_response(NAM_ERR, p);
    2219           0 :                 return;
    2220             :         }
    2221             : 
    2222             :         /*
    2223             :          * Check if the record is active. IF it's already released
    2224             :          * or tombstoned, refuse the release.
    2225             :          */
    2226             : 
    2227           0 :         if (!WINS_STATE_ACTIVE(namerec)) {
    2228           0 :                 DEBUG(3,("wins_process_name_release_request: Refusing request to \
    2229             : release name %s as this record is not active anymore.\n", nmb_namestr(question) ));
    2230           0 :                 send_wins_name_release_response(NAM_ERR, p);
    2231           0 :                 return;
    2232             :         }    
    2233             : 
    2234             :         /*
    2235             :          * Check if the record is a 0x1c group
    2236             :          * and has more then one ip
    2237             :          * remove only this address.
    2238             :          */
    2239             : 
    2240           0 :         if(releasing_group_name && (question->name_type == 0x1c) && (namerec->data.num_ips > 1)) {
    2241           0 :                 remove_ip_from_name_record(namerec, from_ip);
    2242           0 :                 DEBUG(3,("wins_process_name_release_request: Remove IP %s from NAME: %s\n",
    2243             :                                 inet_ntoa(from_ip),nmb_namestr(question)));
    2244           0 :                 wins_hook("delete", namerec, 0);
    2245           0 :                 send_wins_name_release_response(0, p);
    2246           0 :                 return;
    2247             :         }
    2248             : 
    2249             :         /* 
    2250             :          * Send a release response.
    2251             :          * Flag the name as released and update the ttl
    2252             :          */
    2253             : 
    2254           0 :         namerec->data.wins_flags |= WINS_RELEASED;
    2255           0 :         update_name_ttl(namerec, EXTINCTION_INTERVAL);
    2256             : 
    2257           0 :         wins_hook("delete", namerec, 0);
    2258           0 :         send_wins_name_release_response(0, p);
    2259             : }
    2260             : 
    2261             : /*******************************************************************
    2262             :  WINS time dependent processing.
    2263             : ******************************************************************/
    2264             : 
    2265           0 : static int wins_processing_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
    2266             : {
    2267           0 :         time_t t = *(time_t *)state;
    2268           0 :         bool store_record = False;
    2269           0 :         struct name_record *namerec = NULL;
    2270             :         struct in_addr our_fake_ip;
    2271             : 
    2272           0 :         our_fake_ip = interpret_addr2("0.0.0.0");
    2273           0 :         if (kbuf.dsize != sizeof(unstring) + 1) {
    2274           0 :                 return 0;
    2275             :         }
    2276             : 
    2277           0 :         namerec = wins_record_to_name_record(kbuf, dbuf);
    2278           0 :         if (!namerec) {
    2279           0 :                 return 0;
    2280             :         }
    2281             : 
    2282           0 :         if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < t) ) {
    2283           0 :                 if( namerec->data.source == SELF_NAME ) {
    2284           0 :                         DEBUG( 3, ( "wins_processing_traverse_fn: Subnet %s not expiring SELF name %s\n", 
    2285             :                                    wins_server_subnet->subnet_name, nmb_namestr(&namerec->name) ) );
    2286           0 :                         namerec->data.death_time += 300;
    2287           0 :                         store_record = True;
    2288           0 :                         goto done;
    2289           0 :                 } else if (namerec->data.source == DNS_NAME || namerec->data.source == DNSFAIL_NAME) {
    2290           0 :                         DEBUG(3,("wins_processing_traverse_fn: deleting timed out DNS name %s\n",
    2291             :                                         nmb_namestr(&namerec->name)));
    2292           0 :                         remove_name_from_wins_namelist(namerec );
    2293           0 :                         goto done;
    2294             :                 }
    2295             : 
    2296             :                 /* handle records, samba is the wins owner */
    2297           0 :                 if (ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
    2298           0 :                         switch (namerec->data.wins_flags & WINS_STATE_MASK) {
    2299           0 :                                 case WINS_ACTIVE:
    2300           0 :                                         namerec->data.wins_flags&=~WINS_STATE_MASK;
    2301           0 :                                         namerec->data.wins_flags|=WINS_RELEASED;
    2302           0 :                                         namerec->data.death_time = t + EXTINCTION_INTERVAL;
    2303           0 :                                         DEBUG(3,("wins_processing_traverse_fn: expiring %s\n",
    2304             :                                                 nmb_namestr(&namerec->name)));
    2305           0 :                                         store_record = True;
    2306           0 :                                         goto done;
    2307           0 :                                 case WINS_RELEASED:
    2308           0 :                                         namerec->data.wins_flags&=~WINS_STATE_MASK;
    2309           0 :                                         namerec->data.wins_flags|=WINS_TOMBSTONED;
    2310           0 :                                         namerec->data.death_time = t + EXTINCTION_TIMEOUT;
    2311           0 :                                         get_global_id_and_update(&namerec->data.id, True);
    2312           0 :                                         DEBUG(3,("wins_processing_traverse_fn: tombstoning %s\n",
    2313             :                                                 nmb_namestr(&namerec->name)));
    2314           0 :                                         store_record = True;
    2315           0 :                                         goto done;
    2316           0 :                                 case WINS_TOMBSTONED:
    2317           0 :                                         DEBUG(3,("wins_processing_traverse_fn: deleting %s\n",
    2318             :                                                 nmb_namestr(&namerec->name)));
    2319           0 :                                         remove_name_from_wins_namelist(namerec );
    2320           0 :                                         goto done;
    2321             :                         }
    2322             :                 } else {
    2323           0 :                         switch (namerec->data.wins_flags & WINS_STATE_MASK) {
    2324           0 :                                 case WINS_ACTIVE:
    2325             :                                         /* that's not as MS says it should be */
    2326           0 :                                         namerec->data.wins_flags&=~WINS_STATE_MASK;
    2327           0 :                                         namerec->data.wins_flags|=WINS_TOMBSTONED;
    2328           0 :                                         namerec->data.death_time = t + EXTINCTION_TIMEOUT;
    2329           0 :                                         DEBUG(3,("wins_processing_traverse_fn: tombstoning %s\n",
    2330             :                                                 nmb_namestr(&namerec->name)));
    2331           0 :                                         store_record = True;
    2332           0 :                                         goto done;
    2333           0 :                                 case WINS_TOMBSTONED:
    2334           0 :                                         DEBUG(3,("wins_processing_traverse_fn: deleting %s\n",
    2335             :                                                 nmb_namestr(&namerec->name)));
    2336           0 :                                         remove_name_from_wins_namelist(namerec );
    2337           0 :                                         goto done;
    2338           0 :                                 case WINS_RELEASED:
    2339           0 :                                         DEBUG(0,("wins_processing_traverse_fn: %s is in released state and\
    2340             : we are not the wins owner !\n", nmb_namestr(&namerec->name)));
    2341           0 :                                         goto done;
    2342             :                         }
    2343             :                 }
    2344             :         }
    2345             : 
    2346           0 :   done:
    2347             : 
    2348           0 :         if (store_record) {
    2349           0 :                 wins_store_changed_namerec(namerec);
    2350             :         }
    2351             : 
    2352           0 :         SAFE_FREE(namerec->data.ip);
    2353           0 :         SAFE_FREE(namerec);
    2354             : 
    2355           0 :         return 0;
    2356             : }
    2357             : 
    2358             : /*******************************************************************
    2359             :  Time dependent wins processing.
    2360             : ******************************************************************/
    2361             : 
    2362       17145 : void initiate_wins_processing(time_t t)
    2363             : {
    2364             :         static time_t lasttime = 0;
    2365             : 
    2366       17145 :         if (!lasttime) {
    2367          43 :                 lasttime = t;
    2368             :         }
    2369       17145 :         if (t - lasttime < 20) {
    2370       15569 :                 return;
    2371             :         }
    2372             : 
    2373        1576 :         if(!lp_we_are_a_wins_server()) {
    2374        1576 :                 lasttime = t;
    2375        1576 :                 return;
    2376             :         }
    2377             : 
    2378           0 :         tdb_traverse(wins_tdb, wins_processing_traverse_fn, &t);
    2379             : 
    2380           0 :         wins_delete_all_tmp_in_memory_records();
    2381             : 
    2382           0 :         wins_write_database(t, True);
    2383             : 
    2384           0 :         lasttime = t;
    2385             : }
    2386             : 
    2387             : /*******************************************************************
    2388             :  Write out one record.
    2389             : ******************************************************************/
    2390             : 
    2391           0 : void wins_write_name_record(struct name_record *namerec, FILE *fp)
    2392             : {
    2393             :         int i;
    2394             :         struct tm *tm;
    2395             : 
    2396           0 :         DEBUGADD(4,("%-19s ", nmb_namestr(&namerec->name) ));
    2397             : 
    2398           0 :         if( namerec->data.death_time != PERMANENT_TTL ) {
    2399             :                 char *ts, *nl;
    2400             : 
    2401           0 :                 tm = localtime(&namerec->data.death_time);
    2402           0 :                 if (!tm) {
    2403           0 :                         return;
    2404             :                 }
    2405           0 :                 ts = asctime(tm);
    2406           0 :                 if (!ts) {
    2407           0 :                         return;
    2408             :                 }
    2409           0 :                 nl = strrchr( ts, '\n' );
    2410           0 :                 if( NULL != nl ) {
    2411           0 :                         *nl = '\0';
    2412             :                 }
    2413           0 :                 DEBUGADD(4,("TTL = %s  ", ts ));
    2414             :         } else {
    2415           0 :                 DEBUGADD(4,("TTL = PERMANENT                 "));
    2416             :         }
    2417             : 
    2418           0 :         for (i = 0; i < namerec->data.num_ips; i++) {
    2419           0 :                 DEBUGADD(4,("%15s ", inet_ntoa(namerec->data.ip[i]) ));
    2420             :         }
    2421           0 :         DEBUGADD(4,("%2x\n", namerec->data.nb_flags ));
    2422             : 
    2423           0 :         if( namerec->data.source == REGISTER_NAME ) {
    2424             :                 unstring name;
    2425           0 :                 pull_ascii_nstring(name, sizeof(name), namerec->name.name);
    2426           0 :                 fprintf(fp, "\"%s#%02x\" %d ", name,
    2427             :                         namerec->name.name_type, /* Ignore scope. */
    2428           0 :                         (int)namerec->data.death_time);
    2429             : 
    2430           0 :                 for (i = 0; i < namerec->data.num_ips; i++)
    2431           0 :                         fprintf(fp, "%s ", inet_ntoa(namerec->data.ip[i]));
    2432           0 :                 fprintf(fp, "%2xR\n", namerec->data.nb_flags);
    2433             :         }
    2434             : }
    2435             : 
    2436             : /*******************************************************************
    2437             :  Write out the current WINS database.
    2438             : ******************************************************************/
    2439             : 
    2440           0 : static int wins_writedb_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
    2441             : {
    2442           0 :         struct name_record *namerec = NULL;
    2443           0 :         FILE *fp = (FILE *)state;
    2444             : 
    2445           0 :         if (kbuf.dsize != sizeof(unstring) + 1) {
    2446           0 :                 return 0;
    2447             :         }
    2448             : 
    2449           0 :         namerec = wins_record_to_name_record(kbuf, dbuf);
    2450           0 :         if (!namerec) {
    2451           0 :                 return 0;
    2452             :         }
    2453             : 
    2454           0 :         wins_write_name_record(namerec, fp);
    2455             : 
    2456           0 :         SAFE_FREE(namerec->data.ip);
    2457           0 :         SAFE_FREE(namerec);
    2458           0 :         return 0;
    2459             : }
    2460             : 
    2461             : 
    2462          43 : void wins_write_database(time_t t, bool background)
    2463             : {
    2464             :         static time_t last_write_time = 0;
    2465          43 :         char *fname = NULL;
    2466          43 :         char *fnamenew = NULL;
    2467             : 
    2468             :         int fd;
    2469             :         FILE *fp;
    2470             : 
    2471          43 :         if (background) {
    2472           0 :                 if (!last_write_time) {
    2473           0 :                         last_write_time = t;
    2474             :                 }
    2475           0 :                 if (t - last_write_time < 120) {
    2476          43 :                         return;
    2477             :                 }
    2478             : 
    2479             :         }
    2480             : 
    2481          43 :         if(!lp_we_are_a_wins_server()) {
    2482          43 :                 return;
    2483             :         }
    2484             : 
    2485             :         /* We will do the writing in a child process to ensure that the parent doesn't block while this is done */
    2486           0 :         if (background) {
    2487           0 :                 CatchChild();
    2488           0 :                 if (fork()) {
    2489           0 :                         return;
    2490             :                 }
    2491           0 :                 if (tdb_reopen(wins_tdb)) {
    2492           0 :                         DEBUG(0,("wins_write_database: tdb_reopen failed. Error was %s\n",
    2493             :                                 strerror(errno)));
    2494           0 :                         _exit(0);
    2495             :                         return;
    2496             :                 }
    2497             :         }
    2498             : 
    2499           0 :         if (!(fname = state_path(talloc_tos(), WINS_LIST))) {
    2500           0 :                 goto err_exit;
    2501             :         }
    2502             :         /* This is safe as the 0 length means "don't expand". */
    2503           0 :         all_string_sub(fname,"//", "/", 0);
    2504             : 
    2505           0 :         if (asprintf(&fnamenew, "%s.%u", fname, (unsigned int)getpid()) < 0) {
    2506           0 :                 goto err_exit;
    2507             :         }
    2508             : 
    2509           0 :         fd = open(fnamenew, O_WRONLY|O_CREAT, 0644);
    2510           0 :         if (fd == -1) {
    2511           0 :                 DBG_ERR("Can't open %s: %s\n", fnamenew, strerror(errno));
    2512           0 :                 goto err_exit;
    2513             :         }
    2514             : 
    2515           0 :         fp = fdopen(fd, "w");
    2516           0 :         if (fp == NULL) {
    2517           0 :                 DBG_ERR("fdopen failed: %s\n", strerror(errno));
    2518           0 :                 close(fd);
    2519           0 :                 goto err_exit;
    2520             :         }
    2521           0 :         fd = -1;
    2522             : 
    2523           0 :         DEBUG(4,("wins_write_database: Dump of WINS name list.\n"));
    2524             : 
    2525           0 :         fprintf(fp,"VERSION %d %u\n", WINS_VERSION, 0);
    2526             : 
    2527           0 :         tdb_traverse(wins_tdb, wins_writedb_traverse_fn, fp);
    2528             : 
    2529           0 :         fclose(fp);
    2530           0 :         chmod(fnamenew,0644);
    2531           0 :         unlink(fname);
    2532           0 :         rename(fnamenew,fname);
    2533             : 
    2534           0 :   err_exit:
    2535             : 
    2536           0 :         SAFE_FREE(fnamenew);
    2537           0 :         TALLOC_FREE(fname);
    2538             : 
    2539           0 :         if (background) {
    2540           0 :                 _exit(0);
    2541             :         }
    2542             : }
    2543             : 
    2544             : #if 0
    2545             :         Until winsrepl is done.
    2546             : /****************************************************************************
    2547             :  Process a internal Samba message receiving a wins record.
    2548             : ***************************************************************************/
    2549             : 
    2550             : void nmbd_wins_new_entry(struct messaging_context *msg,
    2551             :                                        void *private_data,
    2552             :                                        uint32_t msg_type,
    2553             :                                        struct server_id server_id,
    2554             :                                        DATA_BLOB *data)
    2555             : {
    2556             :         WINS_RECORD *record;
    2557             :         struct name_record *namerec = NULL;
    2558             :         struct name_record *new_namerec = NULL;
    2559             :         struct nmb_name question;
    2560             :         bool overwrite=False;
    2561             :         struct in_addr our_fake_ip;
    2562             :         int i;
    2563             : 
    2564             :         our_fake_ip = interpret_addr2("0.0.0.0");
    2565             :         if (buf==NULL) {
    2566             :                 return;
    2567             :         }
    2568             : 
    2569             :         /* Record should use UNIX codepage. Ensure this is so in the wrepld code. JRA. */
    2570             :         record=(WINS_RECORD *)buf;
    2571             : 
    2572             :         make_nmb_name(&question, record->name, record->type);
    2573             : 
    2574             :         namerec = find_name_on_subnet(wins_server_subnet, &question, FIND_ANY_NAME);
    2575             : 
    2576             :         /* record doesn't exist, add it */
    2577             :         if (namerec == NULL) {
    2578             :                 DEBUG(3,("nmbd_wins_new_entry: adding new replicated record: %s<%02x> for wins server: %s\n", 
    2579             :                           record->name, record->type, inet_ntoa(record->wins_ip)));
    2580             : 
    2581             :                 new_namerec=add_name_to_subnet( wins_server_subnet,
    2582             :                                                 record->name,
    2583             :                                                 record->type,
    2584             :                                                 record->nb_flags, 
    2585             :                                                 EXTINCTION_INTERVAL,
    2586             :                                                 REGISTER_NAME,
    2587             :                                                 record->num_ips,
    2588             :                                                 record->ip);
    2589             : 
    2590             :                 if (new_namerec!=NULL) {
    2591             :                                 update_wins_owner(new_namerec, record->wins_ip);
    2592             :                                 update_wins_flag(new_namerec, record->wins_flags);
    2593             :                                 new_namerec->data.id=record->id;
    2594             : 
    2595             :                                 wins_server_subnet->namelist_changed = True;
    2596             :                         }
    2597             :         }
    2598             : 
    2599             :         /* check if we have a conflict */
    2600             :         if (namerec != NULL) {
    2601             :                 /* both records are UNIQUE */
    2602             :                 if (namerec->data.wins_flags&WINS_UNIQUE && record->wins_flags&WINS_UNIQUE) {
    2603             : 
    2604             :                         /* the database record is a replica */
    2605             :                         if (!ip_equal_v4(namerec->data.wins_ip, our_fake_ip)) {
    2606             :                                 if (namerec->data.wins_flags&WINS_ACTIVE && record->wins_flags&WINS_TOMBSTONED) {
    2607             :                                         if (ip_equal_v4(namerec->data.wins_ip, record->wins_ip))
    2608             :                                                 overwrite=True;
    2609             :                                 } else
    2610             :                                         overwrite=True;
    2611             :                         } else {
    2612             :                         /* we are the wins owner of the database record */
    2613             :                                 /* the 2 records have the same IP address */
    2614             :                                 if (ip_equal_v4(namerec->data.ip[0], record->ip[0])) {
    2615             :                                         if (namerec->data.wins_flags&WINS_ACTIVE && record->wins_flags&WINS_TOMBSTONED)
    2616             :                                                 get_global_id_and_update(&namerec->data.id, True);
    2617             :                                         else
    2618             :                                                 overwrite=True;
    2619             : 
    2620             :                                 } else {
    2621             :                                 /* the 2 records have different IP address */
    2622             :                                         if (namerec->data.wins_flags&WINS_ACTIVE) {
    2623             :                                                 if (record->wins_flags&WINS_TOMBSTONED)
    2624             :                                                         get_global_id_and_update(&namerec->data.id, True);
    2625             :                                                 if (record->wins_flags&WINS_ACTIVE)
    2626             :                                                         /* send conflict challenge to the replica node */
    2627             :                                                         ;
    2628             :                                         } else
    2629             :                                                 overwrite=True;
    2630             :                                 }
    2631             : 
    2632             :                         }
    2633             :                 }
    2634             : 
    2635             :                 /* the replica is a standard group */
    2636             :                 if (record->wins_flags&WINS_NGROUP || record->wins_flags&WINS_SGROUP) {
    2637             :                         /* if the database record is unique and active force a name release */
    2638             :                         if (namerec->data.wins_flags&WINS_UNIQUE)
    2639             :                                 /* send a release name to the unique node */
    2640             :                                 ;
    2641             :                         overwrite=True;
    2642             : 
    2643             :                 }
    2644             : 
    2645             :                 /* the replica is a special group */
    2646             :                 if (record->wins_flags&WINS_SGROUP && namerec->data.wins_flags&WINS_SGROUP) {
    2647             :                         if (namerec->data.wins_flags&WINS_ACTIVE) {
    2648             :                                 for (i=0; i<record->num_ips; i++)
    2649             :                                         if(!find_ip_in_name_record(namerec, record->ip[i]))
    2650             :                                                 add_ip_to_name_record(namerec, record->ip[i]);
    2651             :                         } else {
    2652             :                                 overwrite=True;
    2653             :                         }
    2654             :                 }
    2655             : 
    2656             :                 /* the replica is a multihomed host */
    2657             : 
    2658             :                 /* I'm giving up on multi homed. Too much complex to understand */
    2659             : 
    2660             :                 if (record->wins_flags&WINS_MHOMED) {
    2661             :                         if (! (namerec->data.wins_flags&WINS_ACTIVE)) {
    2662             :                                 if ( !(namerec->data.wins_flags&WINS_RELEASED) && !(namerec->data.wins_flags&WINS_NGROUP))
    2663             :                                         overwrite=True;
    2664             :                         }
    2665             :                         else {
    2666             :                                 if (ip_equal_v4(record->wins_ip, namerec->data.wins_ip))
    2667             :                                         overwrite=True;
    2668             : 
    2669             :                                 if (ip_equal_v4(namerec->data.wins_ip, our_fake_ip))
    2670             :                                         if (namerec->data.wins_flags&WINS_UNIQUE)
    2671             :                                                 get_global_id_and_update(&namerec->data.id, True);
    2672             : 
    2673             :                         }
    2674             : 
    2675             :                         if (record->wins_flags&WINS_ACTIVE && namerec->data.wins_flags&WINS_ACTIVE)
    2676             :                                 if (namerec->data.wins_flags&WINS_UNIQUE ||
    2677             :                                     namerec->data.wins_flags&WINS_MHOMED)
    2678             :                                         if (ip_equal_v4(record->wins_ip, namerec->data.wins_ip))
    2679             :                                                 overwrite=True;
    2680             : 
    2681             :                 }
    2682             : 
    2683             :                 if (overwrite == False)
    2684             :                         DEBUG(3, ("nmbd_wins_new_entry: conflict in adding record: %s<%02x> from wins server: %s\n", 
    2685             :                                   record->name, record->type, inet_ntoa(record->wins_ip)));
    2686             :                 else {
    2687             :                         DEBUG(3, ("nmbd_wins_new_entry: replacing record: %s<%02x> from wins server: %s\n", 
    2688             :                                   record->name, record->type, inet_ntoa(record->wins_ip)));
    2689             : 
    2690             :                         /* remove the old record and add a new one */
    2691             :                         remove_name_from_namelist( wins_server_subnet, namerec );
    2692             :                         new_namerec=add_name_to_subnet( wins_server_subnet, record->name, record->type, record->nb_flags, 
    2693             :                                                 EXTINCTION_INTERVAL, REGISTER_NAME, record->num_ips, record->ip);
    2694             :                         if (new_namerec!=NULL) {
    2695             :                                 update_wins_owner(new_namerec, record->wins_ip);
    2696             :                                 update_wins_flag(new_namerec, record->wins_flags);
    2697             :                                 new_namerec->data.id=record->id;
    2698             : 
    2699             :                                 wins_server_subnet->namelist_changed = True;
    2700             :                         }
    2701             : 
    2702             :                         wins_server_subnet->namelist_changed = True;
    2703             :                 }
    2704             : 
    2705             :         }
    2706             : }
    2707             : #endif

Generated by: LCOV version 1.14