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

Generated by: LCOV version 1.13