nmbd/nmbd_winsserver.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003    NBT netbios routines and daemon - version 2
00004 
00005    Copyright (C) Jeremy Allison 1994-2005
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2 of the License, or
00010    (at your option) any later version.
00011    
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016    
00017    You should have received a copy of the GNU General Public License
00018    along with this program; if not, write to the Free Software
00019    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00020    
00021    Converted to store WINS data in a tdb. Dec 2005. JRA.
00022 */
00023 
00024 #include "includes.h"
00025 
00026 #define WINS_LIST "wins.dat"
00027 #define WINS_VERSION 1
00028 #define WINSDB_VERSION 1
00029 
00030 /****************************************************************************
00031  We don't store the NetBIOS scope in the wins.tdb. We key off the (utf8) netbios
00032  name (65 bytes with the last byte being the name type).
00033 *****************************************************************************/
00034 
00035 TDB_CONTEXT *wins_tdb;
00036 
00037 /****************************************************************************
00038  Delete all the temporary name records on the in-memory linked list.
00039 *****************************************************************************/
00040 
00041 static void wins_delete_all_tmp_in_memory_records(void)
00042 {
00043         struct name_record *nr = NULL;
00044         struct name_record *nrnext = NULL;
00045 
00046         /* Delete all temporary name records on the wins subnet linked list. */
00047         for( nr = wins_server_subnet->namelist; nr; nr = nrnext) {
00048                 nrnext = nr->next;
00049                 DLIST_REMOVE(wins_server_subnet->namelist, nr);
00050                 SAFE_FREE(nr->data.ip);
00051                 SAFE_FREE(nr);
00052         }
00053 }
00054 
00055 /****************************************************************************
00056  Convert a wins.tdb record to a struct name_record. Add in our global_scope().
00057 *****************************************************************************/
00058 
00059 static struct name_record *wins_record_to_name_record(TDB_DATA key, TDB_DATA data)
00060 {
00061         struct name_record *namerec = NULL;
00062         uint16 nb_flags;
00063         unsigned char nr_src;
00064         uint32 death_time, refresh_time;
00065         uint32 id_low, id_high;
00066         uint32 saddr;
00067         uint32 wins_flags;
00068         uint32 num_ips;
00069         size_t len;
00070         int i;
00071 
00072         if (data.dptr == NULL || data.dsize == 0) {
00073                 return NULL;
00074         }
00075 
00076         /* Min size is "wbddddddd" + 1 ip address (4). */
00077         if (data.dsize < 2 + 1 + (7*4) + 4) {
00078                 return NULL;
00079         }
00080 
00081         len = tdb_unpack(data.dptr, data.dsize,
00082                         "wbddddddd",
00083                         &nb_flags,
00084                         &nr_src,
00085                         &death_time,
00086                         &refresh_time,
00087                         &id_low,
00088                         &id_high,
00089                         &saddr,
00090                         &wins_flags,
00091                         &num_ips );
00092 
00093         namerec = SMB_MALLOC_P(struct name_record);
00094         if (!namerec) {
00095                 return NULL;
00096         }
00097         ZERO_STRUCTP(namerec);
00098 
00099         namerec->data.ip = SMB_MALLOC_ARRAY(struct in_addr, num_ips);
00100         if (!namerec->data.ip) {
00101                 SAFE_FREE(namerec);
00102                 return NULL;
00103         }
00104 
00105         namerec->subnet = wins_server_subnet;
00106         push_ascii_nstring(namerec->name.name, key.dptr);
00107         namerec->name.name_type = key.dptr[sizeof(unstring)];
00108         /* Add the scope. */
00109         push_ascii(namerec->name.scope, global_scope(), 64, STR_TERMINATE);
00110 
00111         /* We're using a byte-by-byte compare, so we must be sure that
00112          * unused space doesn't have garbage in it.
00113          */
00114                                                                                                                                
00115         for( i = strlen( namerec->name.name ); i < sizeof( namerec->name.name ); i++ ) {
00116                 namerec->name.name[i] = '\0';
00117         }
00118         for( i = strlen( namerec->name.scope ); i < sizeof( namerec->name.scope ); i++ ) {
00119                 namerec->name.scope[i] = '\0';
00120         }
00121 
00122         namerec->data.nb_flags = nb_flags;
00123         namerec->data.source = (enum name_source)nr_src;
00124         namerec->data.death_time = (time_t)death_time;
00125         namerec->data.refresh_time = (time_t)refresh_time;
00126         namerec->data.id = id_low;
00127 #if defined(HAVE_LONGLONG)
00128         namerec->data.id |= ((SMB_BIG_UINT)id_high << 32);
00129 #endif
00130         namerec->data.wins_ip.s_addr = saddr;
00131         namerec->data.wins_flags = wins_flags,
00132         namerec->data.num_ips = num_ips;
00133 
00134         for (i = 0; i < num_ips; i++) {
00135                 namerec->data.ip[i].s_addr = IVAL(data.dptr, len + (i*4));
00136         }
00137 
00138         return namerec;
00139 }
00140 
00141 /****************************************************************************
00142  Convert a struct name_record to a wins.tdb record. Ignore the scope.
00143 *****************************************************************************/
00144 
00145 static TDB_DATA name_record_to_wins_record(const struct name_record *namerec)
00146 {
00147         TDB_DATA data;
00148         size_t len = 0;
00149         int i;
00150         uint32 id_low = (namerec->data.id & 0xFFFFFFFF);
00151 #if defined(HAVE_LONGLONG)
00152         uint32 id_high = (namerec->data.id >> 32) & 0xFFFFFFFF;
00153 #else
00154         uint32 id_high = 0;
00155 #endif
00156 
00157         ZERO_STRUCT(data);
00158 
00159         len = (2 + 1 + (7*4)); /* "wbddddddd" */
00160         len += (namerec->data.num_ips * 4);
00161 
00162         data.dptr = (char *)SMB_MALLOC(len);
00163         if (!data.dptr) {
00164                 return data;
00165         }
00166         data.dsize = len;
00167 
00168         len = tdb_pack(data.dptr, data.dsize, "wbddddddd",
00169                         namerec->data.nb_flags,
00170                         (unsigned char)namerec->data.source,
00171                         (uint32)namerec->data.death_time,
00172                         (uint32)namerec->data.refresh_time,
00173                         id_low,
00174                         id_high,
00175                         (uint32)namerec->data.wins_ip.s_addr,
00176                         (uint32)namerec->data.wins_flags,
00177                         (uint32)namerec->data.num_ips );
00178 
00179         for (i = 0; i < namerec->data.num_ips; i++) {
00180                 SIVAL(data.dptr, len + (i*4), namerec->data.ip[i].s_addr);
00181         }
00182 
00183         return data;
00184 }
00185 
00186 /****************************************************************************
00187  Create key. Key is UNIX codepage namestring (usually utf8 64 byte len) with 1 byte type.
00188 *****************************************************************************/
00189 
00190 static TDB_DATA name_to_key(const struct nmb_name *nmbname)
00191 {
00192         static char keydata[sizeof(unstring) + 1];
00193         TDB_DATA key;
00194 
00195         memset(keydata, '\0', sizeof(keydata));
00196 
00197         pull_ascii_nstring(keydata, sizeof(unstring), nmbname->name);
00198         strupper_m(keydata);
00199         keydata[sizeof(unstring)] = nmbname->name_type;
00200         key.dptr = keydata;
00201         key.dsize = sizeof(keydata);
00202 
00203         return key;
00204 }
00205 
00206 /****************************************************************************
00207  Lookup a given name in the wins.tdb and create a temporary malloc'ed data struct
00208  on the linked list. We will free this later in XXXX().
00209 *****************************************************************************/
00210 
00211 struct name_record *find_name_on_wins_subnet(const struct nmb_name *nmbname, BOOL self_only)
00212 {
00213         TDB_DATA data, key;
00214         struct name_record *nr = NULL;
00215         struct name_record *namerec = NULL;
00216 
00217         if (!wins_tdb) {
00218                 return NULL;
00219         }
00220 
00221         key = name_to_key(nmbname);
00222         data = tdb_fetch(wins_tdb, key);
00223 
00224         if (data.dsize == 0) {
00225                 return NULL;
00226         }
00227 
00228         namerec = wins_record_to_name_record(key, data);
00229 
00230         /* done with the this */
00231 
00232         SAFE_FREE( data.dptr );
00233 
00234         if (!namerec) {
00235                 return NULL;
00236         }
00237 
00238         /* Self names only - these include permanent names. */
00239         if( self_only && (namerec->data.source != SELF_NAME) && (namerec->data.source != PERMANENT_NAME) ) {
00240                 DEBUG( 9, ( "find_name_on_wins_subnet: self name %s NOT FOUND\n", nmb_namestr(nmbname) ) );
00241                 SAFE_FREE(namerec->data.ip);
00242                 SAFE_FREE(namerec);
00243                 return NULL;
00244         }
00245 
00246         /* Search for this name record on the list. Replace it if found. */
00247 
00248         for( nr = wins_server_subnet->namelist; nr; nr = nr->next) {
00249                 if (memcmp(nmbname->name, nr->name.name, 16) == 0) {
00250                         /* Delete it. */
00251                         DLIST_REMOVE(wins_server_subnet->namelist, nr);
00252                         SAFE_FREE(nr->data.ip);
00253                         SAFE_FREE(nr);
00254                         break;
00255                 }
00256         }
00257         
00258         DLIST_ADD(wins_server_subnet->namelist, namerec);
00259         return namerec;
00260 }
00261 
00262 /****************************************************************************
00263  Overwrite or add a given name in the wins.tdb.
00264 *****************************************************************************/
00265 
00266 static BOOL store_or_replace_wins_namerec(const struct name_record *namerec, int tdb_flag)
00267 {
00268         TDB_DATA key, data;
00269         int ret;
00270 
00271         if (!wins_tdb) {
00272                 return False;
00273         }
00274 
00275         key = name_to_key(&namerec->name);
00276         data = name_record_to_wins_record(namerec);
00277 
00278         if (data.dptr == NULL) {
00279                 return False;
00280         }
00281 
00282         ret = tdb_store(wins_tdb, key, data, tdb_flag);
00283 
00284         SAFE_FREE(data.dptr);
00285         return (ret == 0) ? True : False;
00286 }
00287 
00288 /****************************************************************************
00289  Overwrite a given name in the wins.tdb.
00290 *****************************************************************************/
00291 
00292 BOOL wins_store_changed_namerec(const struct name_record *namerec)
00293 {
00294         return store_or_replace_wins_namerec(namerec, TDB_REPLACE);
00295 }
00296 
00297 /****************************************************************************
00298  Primary interface into creating and overwriting records in the wins.tdb.
00299 *****************************************************************************/
00300 
00301 BOOL add_name_to_wins_subnet(const struct name_record *namerec)
00302 {
00303         return store_or_replace_wins_namerec(namerec, TDB_INSERT);
00304 }
00305 
00306 /****************************************************************************
00307  Delete a given name in the tdb and remove the temporary malloc'ed data struct
00308  on the linked list.
00309 *****************************************************************************/
00310 
00311 BOOL remove_name_from_wins_namelist(struct name_record *namerec)
00312 {
00313         TDB_DATA key;
00314         int ret;
00315 
00316         if (!wins_tdb) {
00317                 return False;
00318         }
00319 
00320         key = name_to_key(&namerec->name);
00321         ret = tdb_delete(wins_tdb, key);
00322 
00323         DLIST_REMOVE(wins_server_subnet->namelist, namerec);
00324 
00325         /* namerec must be freed by the caller */
00326 
00327         return (ret == 0) ? True : False;
00328 }
00329 
00330 /****************************************************************************
00331  Dump out the complete namelist.
00332 *****************************************************************************/
00333 
00334 static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
00335 {
00336         struct name_record *namerec = NULL;
00337         XFILE *fp = (XFILE *)state;
00338 
00339         if (kbuf.dsize != sizeof(unstring) + 1) {
00340                 return 0;
00341         }
00342 
00343         namerec = wins_record_to_name_record(kbuf, dbuf);
00344         if (!namerec) {
00345                 return 0;
00346         }
00347 
00348         dump_name_record(namerec, fp);
00349 
00350         SAFE_FREE(namerec->data.ip);
00351         SAFE_FREE(namerec);
00352         return 0;
00353 }
00354 
00355 void dump_wins_subnet_namelist(XFILE *fp)
00356 {
00357         tdb_traverse(wins_tdb, traverse_fn, (void *)fp);
00358 }
00359 
00360 /****************************************************************************
00361  Change the wins owner address in the record.
00362 *****************************************************************************/
00363 
00364 static void update_wins_owner(struct name_record *namerec, struct in_addr wins_ip)
00365 {
00366         namerec->data.wins_ip=wins_ip;
00367 }
00368 
00369 /****************************************************************************
00370  Create the wins flags based on the nb flags and the input value.
00371 *****************************************************************************/
00372 
00373 static void update_wins_flag(struct name_record *namerec, int flags)
00374 {
00375         namerec->data.wins_flags=0x0;
00376 
00377         /* if it's a group, it can be a normal or a special one */
00378         if (namerec->data.nb_flags & NB_GROUP) {
00379                 if (namerec->name.name_type==0x1C) {
00380                         namerec->data.wins_flags|=WINS_SGROUP;
00381                 } else {
00382                         if (namerec->data.num_ips>1) {
00383                                 namerec->data.wins_flags|=WINS_SGROUP;
00384                         } else {
00385                                 namerec->data.wins_flags|=WINS_NGROUP;
00386                         }
00387                 }
00388         } else {
00389                 /* can be unique or multi-homed */
00390                 if (namerec->data.num_ips>1) {
00391                         namerec->data.wins_flags|=WINS_MHOMED;
00392                 } else {
00393                         namerec->data.wins_flags|=WINS_UNIQUE;
00394                 }
00395         }
00396 
00397         /* the node type are the same bits */
00398         namerec->data.wins_flags|=namerec->data.nb_flags&NB_NODETYPEMASK;
00399 
00400         /* the static bit is elsewhere */
00401         if (namerec->data.death_time == PERMANENT_TTL) {
00402                 namerec->data.wins_flags|=WINS_STATIC;
00403         }
00404 
00405         /* and add the given bits */
00406         namerec->data.wins_flags|=flags;
00407 
00408         DEBUG(8,("update_wins_flag: nbflags: 0x%x, ttl: 0x%d, flags: 0x%x, winsflags: 0x%x\n", 
00409                  namerec->data.nb_flags, (int)namerec->data.death_time, flags, namerec->data.wins_flags));
00410 }
00411 
00412 /****************************************************************************
00413  Return the general ID value and increase it if requested.
00414 *****************************************************************************/
00415 
00416 static void get_global_id_and_update(SMB_BIG_UINT *current_id, BOOL update)
00417 {
00418         /*
00419          * it's kept as a static here, to prevent people from messing
00420          * with the value directly
00421          */
00422 
00423         static SMB_BIG_UINT general_id = 1;
00424 
00425         DEBUG(5,("get_global_id_and_update: updating version ID: %d\n", (int)general_id));
00426         
00427         *current_id = general_id;
00428         
00429         if (update) {
00430                 general_id++;
00431         }
00432 }
00433 
00434 /****************************************************************************
00435  Possibly call the WINS hook external program when a WINS change is made.
00436  Also stores the changed record back in the wins_tdb.
00437 *****************************************************************************/
00438 
00439 static void wins_hook(const char *operation, struct name_record *namerec, int ttl)
00440 {
00441         pstring command;
00442         char *cmd = lp_wins_hook();
00443         char *p, *namestr;
00444         int i;
00445 
00446         wins_store_changed_namerec(namerec);
00447 
00448         if (!cmd || !*cmd) {
00449                 return;
00450         }
00451 
00452         for (p=namerec->name.name; *p; p++) {
00453                 if (!(isalnum((int)*p) || strchr_m("._-",*p))) {
00454                         DEBUG(3,("not calling wins hook for invalid name %s\n", nmb_namestr(&namerec->name)));
00455                         return;
00456                 }
00457         }
00458         
00459         /* Use the name without the nametype (and scope) appended */
00460 
00461         namestr = nmb_namestr(&namerec->name);
00462         if ((p = strchr(namestr, '<'))) {
00463                 *p = 0;
00464         }
00465 
00466         p = command;
00467         p += slprintf(p, sizeof(command)-1, "%s %s %s %02x %d", 
00468                       cmd,
00469                       operation, 
00470                       namestr,
00471                       namerec->name.name_type,
00472                       ttl);
00473 
00474         for (i=0;i<namerec->data.num_ips;i++) {
00475                 p += slprintf(p, sizeof(command) - (p-command) -1, " %s", inet_ntoa(namerec->data.ip[i]));
00476         }
00477 
00478         DEBUG(3,("calling wins hook for %s\n", nmb_namestr(&namerec->name)));
00479         smbrun(command, NULL);
00480 }
00481 
00482 /****************************************************************************
00483 Determine if this packet should be allocated to the WINS server.
00484 *****************************************************************************/
00485 
00486 BOOL packet_is_for_wins_server(struct packet_struct *packet)
00487 {
00488         struct nmb_packet *nmb = &packet->packet.nmb;
00489 
00490         /* Only unicast packets go to a WINS server. */
00491         if((wins_server_subnet == NULL) || (nmb->header.nm_flags.bcast == True)) {
00492                 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #1.\n"));
00493                 return False;
00494         }
00495 
00496         /* Check for node status requests. */
00497         if (nmb->question.question_type != QUESTION_TYPE_NB_QUERY) {
00498                 return False;
00499         }
00500 
00501         switch(nmb->header.opcode) { 
00502                 /*
00503                  * A WINS server issues WACKS, not receives them.
00504                  */
00505                 case NMB_WACK_OPCODE:
00506                         DEBUG(10, ("packet_is_for_wins_server: failing WINS test #2 (WACK).\n"));
00507                         return False;
00508                 /*
00509                  * A WINS server only processes registration and
00510                  * release requests, not responses.
00511                  */
00512                 case NMB_NAME_REG_OPCODE:
00513                 case NMB_NAME_MULTIHOMED_REG_OPCODE:
00514                 case NMB_NAME_REFRESH_OPCODE_8: /* ambiguity in rfc1002 about which is correct. */
00515                 case NMB_NAME_REFRESH_OPCODE_9: /* WinNT uses 8 by default. */
00516                         if(nmb->header.response) {
00517                                 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #3 (response = 1).\n"));
00518                                 return False;
00519                         }
00520                         break;
00521 
00522                 case NMB_NAME_RELEASE_OPCODE:
00523                         if(nmb->header.response) {
00524                                 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #4 (response = 1).\n"));
00525                                 return False;
00526                         }
00527                         break;
00528 
00529                 /*
00530                  * Only process unicast name queries with rd = 1.
00531                  */
00532                 case NMB_NAME_QUERY_OPCODE:
00533                         if(!nmb->header.response && !nmb->header.nm_flags.recursion_desired) {
00534                                 DEBUG(10, ("packet_is_for_wins_server: failing WINS test #5 (response = 1).\n"));
00535                                 return False;
00536                         }
00537                         break;
00538         }
00539 
00540         return True;
00541 }
00542 
00543 /****************************************************************************
00544 Utility function to decide what ttl to give a register/refresh request.
00545 *****************************************************************************/
00546 
00547 static int get_ttl_from_packet(struct nmb_packet *nmb)
00548 {
00549         int ttl = nmb->additional->ttl;
00550 
00551         if (ttl < lp_min_wins_ttl()) {
00552                 ttl = lp_min_wins_ttl();
00553         }
00554 
00555         if (ttl > lp_max_wins_ttl()) {
00556                 ttl = lp_max_wins_ttl();
00557         }
00558 
00559         return ttl;
00560 }
00561 
00562 /****************************************************************************
00563 Load or create the WINS database.
00564 *****************************************************************************/
00565 
00566 BOOL initialise_wins(void)
00567 {
00568         time_t time_now = time(NULL);
00569         XFILE *fp;
00570         pstring line;
00571 
00572         if(!lp_we_are_a_wins_server()) {
00573                 return True;
00574         }
00575 
00576         /* Open the wins.tdb. */
00577         wins_tdb = tdb_open_log(lock_path("wins.tdb"), 0, TDB_DEFAULT|TDB_CLEAR_IF_FIRST, O_CREAT|O_RDWR, 0600);
00578         if (!wins_tdb) {
00579                 DEBUG(0,("initialise_wins: failed to open wins.tdb. Error was %s\n",
00580                         strerror(errno) ));
00581                 return False;
00582         }
00583 
00584         tdb_store_int32(wins_tdb, "WINSDB_VERSION", WINSDB_VERSION);
00585 
00586         add_samba_names_to_subnet(wins_server_subnet);
00587 
00588         if((fp = x_fopen(lock_path(WINS_LIST),O_RDONLY,0)) == NULL) {
00589                 DEBUG(2,("initialise_wins: Can't open wins database file %s. Error was %s\n",
00590                         WINS_LIST, strerror(errno) ));
00591                 return True;
00592         }
00593 
00594         while (!x_feof(fp)) {
00595                 pstring name_str, ip_str, ttl_str, nb_flags_str;
00596                 unsigned int num_ips;
00597                 pstring name;
00598                 struct in_addr *ip_list;
00599                 int type = 0;
00600                 int nb_flags;
00601                 int ttl;
00602                 const char *ptr;
00603                 char *p;
00604                 BOOL got_token;
00605                 BOOL was_ip;
00606                 int i;
00607                 unsigned int hash;
00608                 int version;
00609 
00610                 /* Read a line from the wins.dat file. Strips whitespace
00611                         from the beginning and end of the line.  */
00612                 if (!fgets_slash(line,sizeof(pstring),fp))
00613                         continue;
00614       
00615                 if (*line == '#')
00616                         continue;
00617 
00618                 if (strncmp(line,"VERSION ", 8) == 0) {
00619                         if (sscanf(line,"VERSION %d %u", &version, &hash) != 2 ||
00620                                                 version != WINS_VERSION) {
00621                                 DEBUG(0,("Discarding invalid wins.dat file [%s]\n",line));
00622                                 x_fclose(fp);
00623                                 return True;
00624                         }
00625                         continue;
00626                 }
00627 
00628                 ptr = line;
00629 
00630                 /* 
00631                  * Now we handle multiple IP addresses per name we need
00632                  * to iterate over the line twice. The first time to
00633                  * determine how many IP addresses there are, the second
00634                  * time to actually parse them into the ip_list array.
00635                  */
00636 
00637                 if (!next_token(&ptr,name_str,NULL,sizeof(name_str))) {
00638                         DEBUG(0,("initialise_wins: Failed to parse name when parsing line %s\n", line ));
00639                         continue;
00640                 }
00641 
00642                 if (!next_token(&ptr,ttl_str,NULL,sizeof(ttl_str))) {
00643                         DEBUG(0,("initialise_wins: Failed to parse time to live when parsing line %s\n", line ));
00644                         continue;
00645                 }
00646 
00647                 /*
00648                  * Determine the number of IP addresses per line.
00649                  */
00650                 num_ips = 0;
00651                 do {
00652                         got_token = next_token(&ptr,ip_str,NULL,sizeof(ip_str));
00653                         was_ip = False;
00654 
00655                         if(got_token && strchr(ip_str, '.')) {
00656                                 num_ips++;
00657                                 was_ip = True;
00658                         }
00659                 } while( got_token && was_ip);
00660 
00661                 if(num_ips == 0) {
00662                         DEBUG(0,("initialise_wins: Missing IP address when parsing line %s\n", line ));
00663                         continue;
00664                 }
00665 
00666                 if(!got_token) {
00667                         DEBUG(0,("initialise_wins: Missing nb_flags when parsing line %s\n", line ));
00668                         continue;
00669                 }
00670 
00671                 /* Allocate the space for the ip_list. */
00672                 if((ip_list = SMB_MALLOC_ARRAY( struct in_addr, num_ips)) == NULL) {
00673                         DEBUG(0,("initialise_wins: Malloc fail !\n"));
00674                         x_fclose(fp);
00675                         return False;
00676                 }
00677  
00678                 /* Reset and re-parse the line. */
00679                 ptr = line;
00680                 next_token(&ptr,name_str,NULL,sizeof(name_str)); 
00681                 next_token(&ptr,ttl_str,NULL,sizeof(ttl_str));
00682                 for(i = 0; i < num_ips; i++) {
00683                         next_token(&ptr, ip_str, NULL, sizeof(ip_str));
00684                         ip_list[i] = *interpret_addr2(ip_str);
00685                 }
00686                 next_token(&ptr,nb_flags_str,NULL, sizeof(nb_flags_str));
00687 
00688                 /* 
00689                  * Deal with SELF or REGISTER name encoding. Default is REGISTER
00690                  * for compatibility with old nmbds.
00691                  */
00692 
00693                 if(nb_flags_str[strlen(nb_flags_str)-1] == 'S') {
00694                         DEBUG(5,("initialise_wins: Ignoring SELF name %s\n", line));
00695                         SAFE_FREE(ip_list);
00696                         continue;
00697                 }
00698       
00699                 if(nb_flags_str[strlen(nb_flags_str)-1] == 'R') {
00700                         nb_flags_str[strlen(nb_flags_str)-1] = '\0';
00701                 }
00702       
00703                 /* Netbios name. # divides the name from the type (hex): netbios#xx */
00704                 pstrcpy(name,name_str);
00705       
00706                 if((p = strchr(name,'#')) != NULL) {
00707                         *p = 0;
00708                         sscanf(p+1,"%x",&type);
00709                 }
00710       
00711                 /* Decode the netbios flags (hex) and the time-to-live (in seconds). */
00712                 sscanf(nb_flags_str,"%x",&nb_flags);
00713                 sscanf(ttl_str,"%d",&ttl);
00714 
00715                 /* add all entries that have 60 seconds or more to live */
00716                 if ((ttl - 60) > time_now || ttl == PERMANENT_TTL) {
00717                         if(ttl != PERMANENT_TTL) {
00718                                 ttl -= time_now;
00719                         }
00720     
00721                         DEBUG( 4, ("initialise_wins: add name: %s#%02x ttl = %d first IP %s flags = %2x\n",
00722                                 name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
00723 
00724                         (void)add_name_to_subnet( wins_server_subnet, name, type, nb_flags, 
00725                                         ttl, REGISTER_NAME, num_ips, ip_list );
00726                 } else {
00727                         DEBUG(4, ("initialise_wins: not adding name (ttl problem) "
00728                                 "%s#%02x ttl = %d first IP %s flags = %2x\n",
00729                                 name, type, ttl, inet_ntoa(ip_list[0]), nb_flags));
00730                 }
00731 
00732                 SAFE_FREE(ip_list);
00733         } 
00734     
00735         x_fclose(fp);
00736         return True;
00737 }
00738 
00739 /****************************************************************************
00740 Send a WINS WACK (Wait ACKnowledgement) response.
00741 **************************************************************************/
00742 
00743 static void send_wins_wack_response(int ttl, struct packet_struct *p)
00744 {
00745         struct nmb_packet *nmb = &p->packet.nmb;
00746         unsigned char rdata[2];
00747 
00748         rdata[0] = rdata[1] = 0;
00749 
00750         /* Taken from nmblib.c - we need to send back almost
00751                 identical bytes from the requesting packet header. */
00752 
00753         rdata[0] = (nmb->header.opcode & 0xF) << 3;
00754         if (nmb->header.nm_flags.authoritative && nmb->header.response) {
00755                 rdata[0] |= 0x4;
00756         }
00757         if (nmb->header.nm_flags.trunc) {
00758                 rdata[0] |= 0x2;
00759         }
00760         if (nmb->header.nm_flags.recursion_desired) {
00761                 rdata[0] |= 0x1;
00762         }
00763         if (nmb->header.nm_flags.recursion_available && nmb->header.response) {
00764                 rdata[1] |= 0x80;
00765         }
00766         if (nmb->header.nm_flags.bcast) {
00767                 rdata[1] |= 0x10;
00768         }
00769 
00770         reply_netbios_packet(p,                                /* Packet to reply to. */
00771                                 0,                             /* Result code. */
00772                                 NMB_WAIT_ACK,                  /* nmbd type code. */
00773                                 NMB_WACK_OPCODE,               /* opcode. */
00774                                 ttl,                           /* ttl. */
00775                                 (char *)rdata,                 /* data to send. */
00776                                 2);                            /* data length. */
00777 }
00778 
00779 /****************************************************************************
00780 Send a WINS name registration response.
00781 **************************************************************************/
00782 
00783 static void send_wins_name_registration_response(int rcode, int ttl, struct packet_struct *p)
00784 {
00785         struct nmb_packet *nmb = &p->packet.nmb;
00786         char rdata[6];
00787 
00788         memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
00789 
00790         reply_netbios_packet(p,                                /* Packet to reply to. */
00791                                 rcode,                         /* Result code. */
00792                                 WINS_REG,                      /* nmbd type code. */
00793                                 NMB_NAME_REG_OPCODE,           /* opcode. */
00794                                 ttl,                           /* ttl. */
00795                                 rdata,                         /* data to send. */
00796                                 6);                            /* data length. */
00797 }
00798 
00799 /***********************************************************************
00800  Deal with a name refresh request to a WINS server.
00801 ************************************************************************/
00802 
00803 void wins_process_name_refresh_request( struct subnet_record *subrec,
00804                                         struct packet_struct *p )
00805 {
00806         struct nmb_packet *nmb = &p->packet.nmb;
00807         struct nmb_name *question = &nmb->question.question_name;
00808         BOOL bcast = nmb->header.nm_flags.bcast;
00809         uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
00810         BOOL group = (nb_flags & NB_GROUP) ? True : False;
00811         struct name_record *namerec = NULL;
00812         int ttl = get_ttl_from_packet(nmb);
00813         struct in_addr from_ip;
00814         struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0");
00815 
00816         putip( (char *)&from_ip, &nmb->additional->rdata[2] );
00817 
00818         if(bcast) {
00819                 /*
00820                  * We should only get unicast name refresh packets here.
00821                  * Anyone trying to refresh broadcast should not be going
00822                  * to a WINS server.  Log an error here.
00823                  */
00824                 if( DEBUGLVL( 0 ) ) {
00825                         dbgtext( "wins_process_name_refresh_request: " );
00826                         dbgtext( "Broadcast name refresh request received " );
00827                         dbgtext( "for name %s ", nmb_namestr(question) );
00828                         dbgtext( "from IP %s ", inet_ntoa(from_ip) );
00829                         dbgtext( "on subnet %s.  ", subrec->subnet_name );
00830                         dbgtext( "Error - Broadcasts should not be sent " );
00831                         dbgtext( "to a WINS server\n" );
00832                 }
00833                 return;
00834         }
00835 
00836         if( DEBUGLVL( 3 ) ) {
00837                 dbgtext( "wins_process_name_refresh_request: " );
00838                 dbgtext( "Name refresh for name %s IP %s\n",
00839                          nmb_namestr(question), inet_ntoa(from_ip) );
00840         }
00841 
00842         /* 
00843          * See if the name already exists.
00844          * If not, handle it as a name registration and return.
00845          */
00846         namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
00847 
00848         /*
00849          * If this is a refresh request and the name doesn't exist then
00850          * treat it like a registration request. This allows us to recover 
00851          * from errors (tridge)
00852          */
00853         if(namerec == NULL) {
00854                 if( DEBUGLVL( 3 ) ) {
00855                         dbgtext( "wins_process_name_refresh_request: " );
00856                         dbgtext( "Name refresh for name %s ",
00857                                  nmb_namestr( question ) );
00858                         dbgtext( "and the name does not exist.  Treating " );
00859                         dbgtext( "as registration.\n" );
00860                 }
00861                 wins_process_name_registration_request(subrec,p);
00862                 return;
00863         }
00864 
00865         /*
00866          * if the name is present but not active, simply remove it
00867          * and treat the refresh request as a registration & return.
00868          */
00869         if (namerec != NULL && !WINS_STATE_ACTIVE(namerec)) {
00870                 if( DEBUGLVL( 5 ) ) {
00871                         dbgtext( "wins_process_name_refresh_request: " );
00872                         dbgtext( "Name (%s) in WINS ", nmb_namestr(question) );
00873                         dbgtext( "was not active - removing it.\n" );
00874                 }
00875                 remove_name_from_namelist( subrec, namerec );
00876                 namerec = NULL;
00877                 wins_process_name_registration_request( subrec, p );
00878                 return;
00879         }
00880 
00881         /*
00882          * Check that the group bits for the refreshing name and the
00883          * name in our database match.  If not, refuse the refresh.
00884          * [crh:  Why RFS_ERR instead of ACT_ERR? Is this what MS does?]
00885          */
00886         if( (namerec != NULL) &&
00887             ( (group && !NAME_GROUP(namerec))
00888            || (!group && NAME_GROUP(namerec)) ) ) {
00889                 if( DEBUGLVL( 3 ) ) {
00890                         dbgtext( "wins_process_name_refresh_request: " );
00891                         dbgtext( "Name %s ", nmb_namestr(question) );
00892                         dbgtext( "group bit = %s does not match ",
00893                                  group ? "True" : "False" );
00894                         dbgtext( "group bit in WINS for this name.\n" );
00895                 }
00896                 send_wins_name_registration_response(RFS_ERR, 0, p);
00897                 return;
00898         }
00899 
00900         /*
00901          * For a unique name check that the person refreshing the name is
00902          * one of the registered IP addresses. If not - fail the refresh.
00903          * Do the same for group names with a type of 0x1c.
00904          * Just return success for unique 0x1d refreshes. For normal group
00905          * names update the ttl and return success.
00906          */
00907         if( (!group || (group && (question->name_type == 0x1c)))
00908                         && find_ip_in_name_record(namerec, from_ip) ) {
00909                 /*
00910                  * Update the ttl.
00911                  */
00912                 update_name_ttl(namerec, ttl);
00913 
00914                 /*
00915                  * if the record is a replica:
00916                  * we take ownership and update the version ID.
00917                  */
00918                 if (!ip_equal(namerec->data.wins_ip, our_fake_ip)) {
00919                         update_wins_owner(namerec, our_fake_ip);
00920                         get_global_id_and_update(&namerec->data.id, True);
00921                 }
00922 
00923                 send_wins_name_registration_response(0, ttl, p);
00924                 wins_hook("refresh", namerec, ttl);
00925                 return;
00926         } else if((group && (question->name_type == 0x1c))) {
00927                 /*
00928                  * Added by crh for bug #1079.
00929                  * Fix from Bert Driehuis
00930                  */
00931                 if( DEBUGLVL( 3 ) ) {
00932                         dbgtext( "wins_process_name_refresh_request: " );
00933                         dbgtext( "Name refresh for name %s, ",
00934                                  nmb_namestr(question) );
00935                         dbgtext( "but IP address %s ", inet_ntoa(from_ip) );
00936                         dbgtext( "is not yet associated with " );
00937                         dbgtext( "that name. Treating as registration.\n" );
00938                 }
00939                 wins_process_name_registration_request(subrec,p);
00940                 return;
00941         } else if(group) {
00942                 /* 
00943                  * Normal groups are all registered with an IP address of
00944                  * 255.255.255.255  so we can't search for the IP address.
00945                  */
00946                 update_name_ttl(namerec, ttl);
00947                 wins_hook("refresh", namerec, ttl);
00948                 send_wins_name_registration_response(0, ttl, p);
00949                 return;
00950         } else if(!group && (question->name_type == 0x1d)) {
00951                 /*
00952                  * Special name type - just pretend the refresh succeeded.
00953                  */
00954                 send_wins_name_registration_response(0, ttl, p);
00955                 return;
00956         } else {
00957                 /*
00958                  * Fail the refresh.
00959                  */
00960                 if( DEBUGLVL( 3 ) ) {
00961                         dbgtext( "wins_process_name_refresh_request: " );
00962                         dbgtext( "Name refresh for name %s with IP %s ",
00963                                  nmb_namestr(question), inet_ntoa(from_ip) );
00964                         dbgtext( "and is IP is not known to the name.\n" );
00965                 }
00966                 send_wins_name_registration_response(RFS_ERR, 0, p);
00967                 return;
00968         }
00969 }
00970 
00971 /***********************************************************************
00972  Deal with a name registration request query success to a client that
00973  owned the name.
00974 
00975  We have a locked pointer to the original packet stashed away in the
00976  userdata pointer. The success here is actually a failure as it means
00977  the client we queried wants to keep the name, so we must return
00978  a registration failure to the original requestor.
00979 ************************************************************************/
00980 
00981 static void wins_register_query_success(struct subnet_record *subrec,
00982                                              struct userdata_struct *userdata,
00983                                              struct nmb_name *question_name,
00984                                              struct in_addr ip,
00985                                              struct res_rec *answers)
00986 {
00987         struct packet_struct *orig_reg_packet;
00988 
00989         memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
00990 
00991         DEBUG(3,("wins_register_query_success: Original client at IP %s still wants the \
00992 name %s. Rejecting registration request.\n", inet_ntoa(ip), nmb_namestr(question_name) ));
00993 
00994         send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
00995 
00996         orig_reg_packet->locked = False;
00997         free_packet(orig_reg_packet);
00998 }
00999 
01000 /***********************************************************************
01001  Deal with a name registration request query failure to a client that
01002  owned the name.
01003 
01004  We have a locked pointer to the original packet stashed away in the
01005  userdata pointer. The failure here is actually a success as it means
01006  the client we queried didn't want to keep the name, so we can remove
01007  the old name record and then successfully add the new name.
01008 ************************************************************************/
01009 
01010 static void wins_register_query_fail(struct subnet_record *subrec,
01011                                           struct response_record *rrec,
01012                                           struct nmb_name *question_name,
01013                                           int rcode)
01014 {
01015         struct userdata_struct *userdata = rrec->userdata;
01016         struct packet_struct *orig_reg_packet;
01017         struct name_record *namerec = NULL;
01018 
01019         memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
01020 
01021         /*
01022          * We want to just add the name, as we now know the original owner
01023          * didn't want it. But we can't just do that as an arbitary
01024          * amount of time may have taken place between the name query
01025          * request and this timeout/error response. So we check that
01026          * the name still exists and is in the same state - if so
01027          * we remove it and call wins_process_name_registration_request()
01028          * as we know it will do the right thing now.
01029          */
01030 
01031         namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
01032 
01033         if ((namerec != NULL) && (namerec->data.source == REGISTER_NAME) &&
01034                         ip_equal(rrec->packet->ip, *namerec->data.ip)) {
01035                 remove_name_from_namelist( subrec, namerec);
01036                 namerec = NULL;
01037         }
01038 
01039         if(namerec == NULL) {
01040                 wins_process_name_registration_request(subrec, orig_reg_packet);
01041         } else {
01042                 DEBUG(2,("wins_register_query_fail: The state of the WINS database changed between "
01043                         "querying for name %s in order to replace it and this reply.\n",
01044                         nmb_namestr(question_name) ));
01045         }
01046 
01047         orig_reg_packet->locked = False;
01048         free_packet(orig_reg_packet);
01049 }
01050 
01051 /***********************************************************************
01052  Deal with a name registration request to a WINS server.
01053 
01054  Use the following pseudocode :
01055 
01056  registering_group
01057      |
01058      |
01059      +--------name exists
01060      |                  |
01061      |                  |
01062      |                  +--- existing name is group
01063      |                  |                      |
01064      |                  |                      |
01065      |                  |                      +--- add name (return).
01066      |                  |
01067      |                  |
01068      |                  +--- exiting name is unique
01069      |                                         |
01070      |                                         |
01071      |                                         +--- query existing owner (return).
01072      |
01073      |
01074      +--------name doesn't exist
01075                         |
01076                         |
01077                         +--- add name (return).
01078 
01079  registering_unique
01080      |
01081      |
01082      +--------name exists
01083      |                  |
01084      |                  |
01085      |                  +--- existing name is group 
01086      |                  |                      |
01087      |                  |                      |
01088      |                  |                      +--- fail add (return).
01089      |                  | 
01090      |                  |
01091      |                  +--- exiting name is unique
01092      |                                         |
01093      |                                         |
01094      |                                         +--- query existing owner (return).
01095      |
01096      |
01097      +--------name doesn't exist
01098                         |
01099                         |
01100                         +--- add name (return).
01101 
01102  As can be seen from the above, the two cases may be collapsed onto each
01103  other with the exception of the case where the name already exists and
01104  is a group name. This case we handle with an if statement.
01105  
01106 ************************************************************************/
01107 
01108 void wins_process_name_registration_request(struct subnet_record *subrec,
01109                                             struct packet_struct *p)
01110 {
01111         unstring name;
01112         struct nmb_packet *nmb = &p->packet.nmb;
01113         struct nmb_name *question = &nmb->question.question_name;
01114         BOOL bcast = nmb->header.nm_flags.bcast;
01115         uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
01116         int ttl = get_ttl_from_packet(nmb);
01117         struct name_record *namerec = NULL;
01118         struct in_addr from_ip;
01119         BOOL registering_group_name = (nb_flags & NB_GROUP) ? True : False;
01120         struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0");
01121 
01122         putip((char *)&from_ip,&nmb->additional->rdata[2]);
01123 
01124         if(bcast) {
01125                 /*
01126                  * We should only get unicast name registration packets here.
01127                  * Anyone trying to register broadcast should not be going to a WINS
01128                  * server. Log an error here.
01129                  */
01130 
01131                 DEBUG(0,("wins_process_name_registration_request: broadcast name registration request \
01132 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
01133                         nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
01134                 return;
01135         }
01136 
01137         DEBUG(3,("wins_process_name_registration_request: %s name registration for name %s \
01138 IP %s\n", registering_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) ));
01139 
01140         /*
01141          * See if the name already exists.
01142          */
01143 
01144         namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
01145 
01146         /*
01147          * if the record exists but NOT in active state,
01148          * consider it dead.
01149          */
01150         if ( (namerec != NULL) && !WINS_STATE_ACTIVE(namerec)) {
01151                 DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was \
01152 not active - removing it.\n", nmb_namestr(question) ));
01153                 remove_name_from_namelist( subrec, namerec );
01154                 namerec = NULL;
01155         }
01156 
01157         /*
01158          * Deal with the case where the name found was a dns entry.
01159          * Remove it as we now have a NetBIOS client registering the
01160          * name.
01161          */
01162 
01163         if( (namerec != NULL) && ( (namerec->data.source == DNS_NAME) || (namerec->data.source == DNSFAIL_NAME) ) ) {
01164                 DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was \
01165 a dns lookup - removing it.\n", nmb_namestr(question) ));
01166                 remove_name_from_namelist( subrec, namerec );
01167                 namerec = NULL;
01168         }
01169 
01170         /*
01171          * Reject if the name exists and is not a REGISTER_NAME.
01172          * (ie. Don't allow any static names to be overwritten.
01173          */
01174 
01175         if((namerec != NULL) && (namerec->data.source != REGISTER_NAME)) {
01176                 DEBUG( 3, ( "wins_process_name_registration_request: Attempt \
01177 to register name %s. Name already exists in WINS with source type %d.\n",
01178                         nmb_namestr(question), namerec->data.source ));
01179                 send_wins_name_registration_response(RFS_ERR, 0, p);
01180                 return;
01181         }
01182 
01183         /*
01184          * Special policy decisions based on MS documentation.
01185          * 1). All group names (except names ending in 0x1c) are added as 255.255.255.255.
01186          * 2). All unique names ending in 0x1d are ignored, although a positive response is sent.
01187          */
01188 
01189         /*
01190          * A group name is always added as the local broadcast address, except
01191          * for group names ending in 0x1c.
01192          * Group names with type 0x1c are registered with individual IP addresses.
01193          */
01194 
01195         if(registering_group_name && (question->name_type != 0x1c)) {
01196                 from_ip = *interpret_addr2("255.255.255.255");
01197         }
01198 
01199         /*
01200          * Ignore all attempts to register a unique 0x1d name, although return success.
01201          */
01202 
01203         if(!registering_group_name && (question->name_type == 0x1d)) {
01204                 DEBUG(3,("wins_process_name_registration_request: Ignoring request \
01205 to register name %s from IP %s.\n", nmb_namestr(question), inet_ntoa(p->ip) ));
01206                 send_wins_name_registration_response(0, ttl, p);
01207                 return;
01208         }
01209 
01210         /*
01211          * Next two cases are the 'if statement' mentioned above.
01212          */
01213 
01214         if((namerec != NULL) && NAME_GROUP(namerec)) {
01215                 if(registering_group_name) {
01216                         /*
01217                          * If we are adding a group name, the name exists and is also a group entry just add this
01218                          * IP address to it and update the ttl.
01219                          */
01220 
01221                         DEBUG(3,("wins_process_name_registration_request: Adding IP %s to group name %s.\n",
01222                                 inet_ntoa(from_ip), nmb_namestr(question) ));
01223 
01224                         /* 
01225                          * Check the ip address is not already in the group.
01226                          */
01227 
01228                         if(!find_ip_in_name_record(namerec, from_ip)) {
01229                                 add_ip_to_name_record(namerec, from_ip);
01230                                 /* we need to update the record for replication */
01231                                 get_global_id_and_update(&namerec->data.id, True);
01232 
01233                                 /*
01234                                  * if the record is a replica, we must change
01235                                  * the wins owner to us to make the replication updates
01236                                  * it on the other wins servers.
01237                                  * And when the partner will receive this record,
01238                                  * it will update its own record.
01239                                  */
01240 
01241                                 update_wins_owner(namerec, our_fake_ip);
01242                         }
01243                         update_name_ttl(namerec, ttl);
01244                         wins_hook("refresh", namerec, ttl);
01245                         send_wins_name_registration_response(0, ttl, p);
01246                         return;
01247                 } else {
01248 
01249                         /*
01250                          * If we are adding a unique name, the name exists in the WINS db 
01251                          * and is a group name then reject the registration.
01252                          *
01253                          * explanation: groups have a higher priority than unique names.
01254                          */
01255 
01256                         DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
01257 already exists in WINS as a GROUP name.\n", nmb_namestr(question) ));
01258                         send_wins_name_registration_response(RFS_ERR, 0, p);
01259                         return;
01260                 } 
01261         }
01262 
01263         /*
01264          * From here on down we know that if the name exists in the WINS db it is
01265          * a unique name, not a group name.
01266          */
01267 
01268         /* 
01269          * If the name exists and is one of our names then check the
01270          * registering IP address. If it's not one of ours then automatically
01271          * reject without doing the query - we know we will reject it.
01272          */
01273 
01274         if ( namerec != NULL ) {
01275                 pull_ascii_nstring(name, sizeof(name), namerec->name.name);
01276                 if( is_myname(name) ) {
01277                         if(!ismyip(from_ip)) {
01278                                 DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \
01279 is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
01280                                 send_wins_name_registration_response(RFS_ERR, 0, p);
01281                                 return;
01282                         } else {
01283                                 /*
01284                                  * It's one of our names and one of our IP's - update the ttl.
01285                                  */
01286                                 update_name_ttl(namerec, ttl);
01287                                 wins_hook("refresh", namerec, ttl);
01288                                 send_wins_name_registration_response(0, ttl, p);
01289                                 return;
01290                         }
01291                 }
01292         } else {
01293                 name[0] = '\0';
01294         }
01295 
01296         /*
01297          * If the name exists and it is a unique registration and the registering IP 
01298          * is the same as the (single) already registered IP then just update the ttl.
01299          *
01300          * But not if the record is an active replica. IF it's a replica, it means it can be
01301          * the same client which has moved and not yet expired. So we don't update
01302          * the ttl in this case and go beyond to do a WACK and query the old client
01303          */
01304 
01305         if( !registering_group_name
01306                         && (namerec != NULL)
01307                         && (namerec->data.num_ips == 1)
01308                         && ip_equal( namerec->data.ip[0], from_ip )
01309                         && ip_equal(namerec->data.wins_ip, our_fake_ip) ) {
01310                 update_name_ttl( namerec, ttl );
01311                 wins_hook("refresh", namerec, ttl);
01312                 send_wins_name_registration_response( 0, ttl, p );
01313                 return;
01314         }
01315 
01316         /*
01317          * Finally if the name exists do a query to the registering machine 
01318          * to see if they still claim to have the name.
01319          */
01320 
01321         if( namerec != NULL ) {
01322                 long *ud[(sizeof(struct userdata_struct) + sizeof(struct packet_struct *))/sizeof(long *) + 1];
01323                 struct userdata_struct *userdata = (struct userdata_struct *)ud;
01324 
01325                 /*
01326                  * First send a WACK to the registering machine.
01327                  */
01328 
01329                 send_wins_wack_response(60, p);
01330 
01331                 /*
01332                  * When the reply comes back we need the original packet.
01333                  * Lock this so it won't be freed and then put it into
01334                  * the userdata structure.
01335                  */
01336 
01337                 p->locked = True;
01338 
01339                 userdata = (struct userdata_struct *)ud;
01340 
01341                 userdata->copy_fn = NULL;
01342                 userdata->free_fn = NULL;
01343                 userdata->userdata_len = sizeof(struct packet_struct *);
01344                 memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
01345 
01346                 /*
01347                  * Use the new call to send a query directly to an IP address.
01348                  * This sends the query directly to the IP address, and ensures
01349                  * the recursion desired flag is not set (you were right Luke :-).
01350                  * This function should *only* be called from the WINS server
01351                  * code. JRA.
01352                  */
01353 
01354                 pull_ascii_nstring(name, sizeof(name), question->name);
01355                 query_name_from_wins_server( *namerec->data.ip,
01356                                 name,
01357                                 question->name_type, 
01358                                 wins_register_query_success,
01359                                 wins_register_query_fail,
01360                                 userdata );
01361                 return;
01362         }
01363 
01364         /*
01365          * Name did not exist - add it.
01366          */
01367 
01368         pull_ascii_nstring(name, sizeof(name), question->name);
01369         add_name_to_subnet( subrec, name, question->name_type,
01370                         nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
01371 
01372         if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) {
01373                 get_global_id_and_update(&namerec->data.id, True);
01374                 update_wins_owner(namerec, our_fake_ip);
01375                 update_wins_flag(namerec, WINS_ACTIVE);
01376                 wins_hook("add", namerec, ttl);
01377         }
01378 
01379         send_wins_name_registration_response(0, ttl, p);
01380 }
01381 
01382 /***********************************************************************
01383  Deal with a mutihomed name query success to the machine that
01384  requested the multihomed name registration.
01385 
01386  We have a locked pointer to the original packet stashed away in the
01387  userdata pointer.
01388 ************************************************************************/
01389 
01390 static void wins_multihomed_register_query_success(struct subnet_record *subrec,
01391                                              struct userdata_struct *userdata,
01392                                              struct nmb_name *question_name,
01393                                              struct in_addr ip,
01394                                              struct res_rec *answers)
01395 {
01396         struct packet_struct *orig_reg_packet;
01397         struct nmb_packet *nmb;
01398         struct name_record *namerec = NULL;
01399         struct in_addr from_ip;
01400         int ttl;
01401         struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0");
01402 
01403         memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
01404 
01405         nmb = &orig_reg_packet->packet.nmb;
01406 
01407         putip((char *)&from_ip,&nmb->additional->rdata[2]);
01408         ttl = get_ttl_from_packet(nmb);
01409 
01410         /*
01411          * We want to just add the new IP, as we now know the requesting
01412          * machine claims to own it. But we can't just do that as an arbitary
01413          * amount of time may have taken place between the name query
01414          * request and this response. So we check that
01415          * the name still exists and is in the same state - if so
01416          * we just add the extra IP and update the ttl.
01417          */
01418 
01419         namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME);
01420 
01421         if( (namerec == NULL) || (namerec->data.source != REGISTER_NAME) || !WINS_STATE_ACTIVE(namerec) ) {
01422                 DEBUG(3,("wins_multihomed_register_query_success: name %s is not in the correct state to add \
01423 a subsequent IP address.\n", nmb_namestr(question_name) ));
01424                 send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
01425 
01426                 orig_reg_packet->locked = False;
01427                 free_packet(orig_reg_packet);
01428 
01429                 return;
01430         }
01431 
01432         if(!find_ip_in_name_record(namerec, from_ip)) {
01433                 add_ip_to_name_record(namerec, from_ip);
01434         }
01435 
01436         get_global_id_and_update(&namerec->data.id, True);
01437         update_wins_owner(namerec, our_fake_ip);
01438         update_wins_flag(namerec, WINS_ACTIVE);
01439         update_name_ttl(namerec, ttl);
01440         wins_hook("add", namerec, ttl);
01441         send_wins_name_registration_response(0, ttl, orig_reg_packet);
01442 
01443         orig_reg_packet->locked = False;
01444         free_packet(orig_reg_packet);
01445 }
01446 
01447 /***********************************************************************
01448  Deal with a name registration request query failure to a client that
01449  owned the name.
01450 
01451  We have a locked pointer to the original packet stashed away in the
01452  userdata pointer.
01453 ************************************************************************/
01454 
01455 static void wins_multihomed_register_query_fail(struct subnet_record *subrec,
01456                                           struct response_record *rrec,
01457                                           struct nmb_name *question_name,
01458                                           int rcode)
01459 {
01460         struct userdata_struct *userdata = rrec->userdata;
01461         struct packet_struct *orig_reg_packet;
01462 
01463         memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *));
01464 
01465         DEBUG(3,("wins_multihomed_register_query_fail: Registering machine at IP %s failed to answer \
01466 query successfully for name %s.\n", inet_ntoa(orig_reg_packet->ip), nmb_namestr(question_name) ));
01467         send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet);
01468 
01469         orig_reg_packet->locked = False;
01470         free_packet(orig_reg_packet);
01471         return;
01472 }
01473 
01474 /***********************************************************************
01475  Deal with a multihomed name registration request to a WINS server.
01476  These cannot be group name registrations.
01477 ***********************************************************************/
01478 
01479 void wins_process_multihomed_name_registration_request( struct subnet_record *subrec,
01480                                                         struct packet_struct *p)
01481 {
01482         struct nmb_packet *nmb = &p->packet.nmb;
01483         struct nmb_name *question = &nmb->question.question_name;
01484         BOOL bcast = nmb->header.nm_flags.bcast;
01485         uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
01486         int ttl = get_ttl_from_packet(nmb);
01487         struct name_record *namerec = NULL;
01488         struct in_addr from_ip;
01489         BOOL group = (nb_flags & NB_GROUP) ? True : False;
01490         struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0");
01491         unstring qname;
01492 
01493         putip((char *)&from_ip,&nmb->additional->rdata[2]);
01494 
01495         if(bcast) {
01496                 /*
01497                  * We should only get unicast name registration packets here.
01498                  * Anyone trying to register broadcast should not be going to a WINS
01499                  * server. Log an error here.
01500                  */
01501 
01502                 DEBUG(0,("wins_process_multihomed_name_registration_request: broadcast name registration request \
01503 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
01504                         nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
01505                 return;
01506         }
01507 
01508         /*
01509          * Only unique names should be registered multihomed.
01510          */
01511 
01512         if(group) {
01513                 DEBUG(0,("wins_process_multihomed_name_registration_request: group name registration request \
01514 received for name %s from IP %s on subnet %s. Errror - group names should not be multihomed.\n",
01515                         nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
01516                 return;
01517         }
01518 
01519         DEBUG(3,("wins_process_multihomed_name_registration_request: name registration for name %s \
01520 IP %s\n", nmb_namestr(question), inet_ntoa(from_ip) ));
01521 
01522         /*
01523          * Deal with policy regarding 0x1d names.
01524          */
01525 
01526         if(question->name_type == 0x1d) {
01527                 DEBUG(3,("wins_process_multihomed_name_registration_request: Ignoring request \
01528 to register name %s from IP %s.", nmb_namestr(question), inet_ntoa(p->ip) ));
01529                 send_wins_name_registration_response(0, ttl, p);  
01530                 return;
01531         }
01532 
01533         /*
01534          * See if the name already exists.
01535          */
01536 
01537         namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
01538 
01539         /*
01540          * if the record exists but NOT in active state,
01541          * consider it dead.
01542          */
01543 
01544         if ((namerec != NULL) && !WINS_STATE_ACTIVE(namerec)) {
01545                 DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was not active - removing it.\n", nmb_namestr(question)));
01546                 remove_name_from_namelist(subrec, namerec);
01547                 namerec = NULL;
01548         }
01549   
01550         /*
01551          * Deal with the case where the name found was a dns entry.
01552          * Remove it as we now have a NetBIOS client registering the
01553          * name.
01554          */
01555 
01556         if( (namerec != NULL) && ( (namerec->data.source == DNS_NAME) || (namerec->data.source == DNSFAIL_NAME) ) ) {
01557                 DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was a dns lookup \
01558 - removing it.\n", nmb_namestr(question) ));
01559                 remove_name_from_namelist( subrec, namerec);
01560                 namerec = NULL;
01561         }
01562 
01563         /*
01564          * Reject if the name exists and is not a REGISTER_NAME.
01565          * (ie. Don't allow any static names to be overwritten.
01566          */
01567 
01568         if( (namerec != NULL) && (namerec->data.source != REGISTER_NAME) ) {
01569                 DEBUG( 3, ( "wins_process_multihomed_name_registration_request: Attempt \
01570 to register name %s. Name already exists in WINS with source type %d.\n",
01571                         nmb_namestr(question), namerec->data.source ));
01572                 send_wins_name_registration_response(RFS_ERR, 0, p);
01573                 return;
01574         }
01575 
01576         /*
01577          * Reject if the name exists and is a GROUP name and is active.
01578          */
01579 
01580         if((namerec != NULL) && NAME_GROUP(namerec) && WINS_STATE_ACTIVE(namerec)) {
01581                 DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
01582 already exists in WINS as a GROUP name.\n", nmb_namestr(question) ));
01583                 send_wins_name_registration_response(RFS_ERR, 0, p);
01584                 return;
01585         } 
01586 
01587         /*
01588          * From here on down we know that if the name exists in the WINS db it is
01589          * a unique name, not a group name.
01590          */
01591 
01592         /*
01593          * If the name exists and is one of our names then check the
01594          * registering IP address. If it's not one of ours then automatically
01595          * reject without doing the query - we know we will reject it.
01596          */
01597 
01598         if((namerec != NULL) && (is_myname(namerec->name.name)) ) {
01599                 if(!ismyip(from_ip)) {
01600                         DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
01601 is one of our (WINS server) names. Denying registration.\n", nmb_namestr(question) ));
01602                         send_wins_name_registration_response(RFS_ERR, 0, p);
01603                         return;
01604                 } else {
01605                         /*
01606                          * It's one of our names and one of our IP's. Ensure the IP is in the record and
01607                          *  update the ttl. Update the version ID to force replication.
01608                          */
01609                         update_name_ttl(namerec, ttl);
01610 
01611                         if(!find_ip_in_name_record(namerec, from_ip)) {
01612                                 get_global_id_and_update(&namerec->data.id, True);
01613                                 update_wins_owner(namerec, our_fake_ip);
01614                                 update_wins_flag(namerec, WINS_ACTIVE);
01615 
01616                                 add_ip_to_name_record(namerec, from_ip);
01617                         }
01618 
01619                         wins_hook("refresh", namerec, ttl);
01620                         send_wins_name_registration_response(0, ttl, p);
01621                         return;
01622                 }
01623         }
01624 
01625         /*
01626          * If the name exists and is active, check if the IP address is already registered
01627          * to that name. If so then update the ttl and reply success.
01628          */
01629 
01630         if((namerec != NULL) && find_ip_in_name_record(namerec, from_ip) && WINS_STATE_ACTIVE(namerec)) {
01631                 update_name_ttl(namerec, ttl);
01632 
01633                 /*
01634                  * If it's a replica, we need to become the wins owner
01635                  * to force the replication
01636                  */
01637                 if (!ip_equal(namerec->data.wins_ip, our_fake_ip)) {
01638                         get_global_id_and_update(&namerec->data.id, True);
01639                         update_wins_owner(namerec, our_fake_ip);
01640                         update_wins_flag(namerec, WINS_ACTIVE);
01641                 }
01642     
01643                 wins_hook("refresh", namerec, ttl);
01644                 send_wins_name_registration_response(0, ttl, p);
01645                 return;
01646         }
01647 
01648         /*
01649          * If the name exists do a query to the owner
01650          * to see if they still want the name.
01651          */
01652 
01653         if(namerec != NULL) {
01654                 long *ud[(sizeof(struct userdata_struct) + sizeof(struct packet_struct *))/sizeof(long *) + 1];
01655                 struct userdata_struct *userdata = (struct userdata_struct *)ud;
01656 
01657                 /*
01658                  * First send a WACK to the registering machine.
01659                  */
01660 
01661                 send_wins_wack_response(60, p);
01662 
01663                 /*
01664                  * When the reply comes back we need the original packet.
01665                  * Lock this so it won't be freed and then put it into
01666                  * the userdata structure.
01667                  */
01668 
01669                 p->locked = True;
01670 
01671                 userdata = (struct userdata_struct *)ud;
01672 
01673                 userdata->copy_fn = NULL;
01674                 userdata->free_fn = NULL;
01675                 userdata->userdata_len = sizeof(struct packet_struct *);
01676                 memcpy(userdata->data, (char *)&p, sizeof(struct packet_struct *) );
01677 
01678                 /* 
01679                  * Use the new call to send a query directly to an IP address.
01680                  * This sends the query directly to the IP address, and ensures
01681                  * the recursion desired flag is not set (you were right Luke :-).
01682                  * This function should *only* be called from the WINS server
01683                  * code. JRA.
01684                  *
01685                  * Note that this packet is sent to the current owner of the name,
01686                  * not the person who sent the packet 
01687                  */
01688 
01689                 pull_ascii_nstring( qname, sizeof(qname), question->name);
01690                 query_name_from_wins_server( namerec->data.ip[0],
01691                                 qname,
01692                                 question->name_type, 
01693                                 wins_multihomed_register_query_success,
01694                                 wins_multihomed_register_query_fail,
01695                                 userdata );
01696 
01697                 return;
01698         }
01699 
01700         /*
01701          * Name did not exist - add it.
01702          */
01703 
01704         pull_ascii_nstring( qname, sizeof(qname), question->name);
01705         add_name_to_subnet( subrec, qname, question->name_type,
01706                         nb_flags, ttl, REGISTER_NAME, 1, &from_ip);
01707 
01708         if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) {
01709                 get_global_id_and_update(&namerec->data.id, True);
01710                 update_wins_owner(namerec, our_fake_ip);
01711                 update_wins_flag(namerec, WINS_ACTIVE);
01712                 wins_hook("add", namerec, ttl);
01713         }
01714 
01715         send_wins_name_registration_response(0, ttl, p);
01716 }
01717 
01718 /***********************************************************************
01719  Fetch all *<1b> names from the WINS db and store on the namelist.
01720 ***********************************************************************/
01721 
01722 static int fetch_1b_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
01723 {
01724         struct name_record *namerec = NULL;
01725 
01726         if (kbuf.dsize != sizeof(unstring) + 1) {
01727                 return 0;
01728         }
01729 
01730         /* Filter out all non-1b names. */
01731         if (kbuf.dptr[sizeof(unstring)] != 0x1b) {
01732                 return 0;
01733         }
01734 
01735         namerec = wins_record_to_name_record(kbuf, dbuf);
01736         if (!namerec) {
01737                 return 0;
01738         }
01739 
01740         DLIST_ADD(wins_server_subnet->namelist, namerec);
01741         return 0;
01742 }
01743 
01744 void fetch_all_active_wins_1b_names(void)
01745 {
01746         tdb_traverse(wins_tdb, fetch_1b_traverse_fn, NULL);
01747 }
01748 
01749 /***********************************************************************
01750  Deal with the special name query for *<1b>.
01751 ***********************************************************************/
01752    
01753 static void process_wins_dmb_query_request(struct subnet_record *subrec,  
01754                                            struct packet_struct *p)
01755 {  
01756         struct name_record *namerec = NULL;
01757         char *prdata;
01758         int num_ips;
01759 
01760         /*
01761          * Go through all the ACTIVE names in the WINS db looking for those
01762          * ending in <1b>. Use this to calculate the number of IP
01763          * addresses we need to return.
01764          */
01765 
01766         num_ips = 0;
01767 
01768         /* First, clear the in memory list - we're going to re-populate
01769            it with the tdb_traversal in fetch_all_active_wins_1b_names. */
01770 
01771         wins_delete_all_tmp_in_memory_records();
01772 
01773         fetch_all_active_wins_1b_names();
01774 
01775         for( namerec = subrec->namelist; namerec; namerec = namerec->next ) {
01776                 if( WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) {
01777                         num_ips += namerec->data.num_ips;
01778                 }
01779         }
01780 
01781         if(num_ips == 0) {
01782                 /*
01783                  * There are no 0x1b names registered. Return name query fail.
01784                  */
01785                 send_wins_name_query_response(NAM_ERR, p, NULL);
01786                 return;
01787         }
01788 
01789         if((prdata = (char *)SMB_MALLOC( num_ips * 6 )) == NULL) {
01790                 DEBUG(0,("process_wins_dmb_query_request: Malloc fail !.\n"));
01791                 return;
01792         }
01793 
01794         /*
01795          * Go through all the names again in the WINS db looking for those
01796          * ending in <1b>. Add their IP addresses into the list we will
01797          * return.
01798          */ 
01799 
01800         num_ips = 0;
01801         for( namerec = subrec->namelist; namerec; namerec = namerec->next ) {
01802                 if( WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) {
01803                         int i;
01804                         for(i = 0; i < namerec->data.num_ips; i++) {
01805                                 set_nb_flags(&prdata[num_ips * 6],namerec->data.nb_flags);
01806                                 putip((char *)&prdata[(num_ips * 6) + 2], &namerec->data.ip[i]);
01807                                 num_ips++;
01808                         }
01809                 }
01810         }
01811 
01812         /*
01813          * Send back the reply containing the IP list.
01814          */
01815 
01816         reply_netbios_packet(p,                                /* Packet to reply to. */
01817                                 0,                             /* Result code. */
01818                                 WINS_QUERY,                    /* nmbd type code. */
01819                                 NMB_NAME_QUERY_OPCODE,         /* opcode. */
01820                                 lp_min_wins_ttl(),             /* ttl. */
01821                                 prdata,                        /* data to send. */
01822                                 num_ips*6);                    /* data length. */
01823 
01824         SAFE_FREE(prdata);
01825 }
01826 
01827 /****************************************************************************
01828 Send a WINS name query response.
01829 **************************************************************************/
01830 
01831 void send_wins_name_query_response(int rcode, struct packet_struct *p, 
01832                                           struct name_record *namerec)
01833 {
01834         char rdata[6];
01835         char *prdata = rdata;
01836         int reply_data_len = 0;
01837         int ttl = 0;
01838         int i;
01839 
01840         memset(rdata,'\0',6);
01841 
01842         if(rcode == 0) {
01843                 ttl = (namerec->data.death_time != PERMANENT_TTL) ?  namerec->data.death_time - p->timestamp : lp_max_wins_ttl();
01844 
01845                 /* Copy all known ip addresses into the return data. */
01846                 /* Optimise for the common case of one IP address so we don't need a malloc. */
01847 
01848                 if( namerec->data.num_ips == 1 ) {
01849                         prdata = rdata;
01850                 } else {
01851                         if((prdata = (char *)SMB_MALLOC( namerec->data.num_ips * 6 )) == NULL) {
01852                                 DEBUG(0,("send_wins_name_query_response: malloc fail !\n"));
01853                                 return;
01854                         }
01855                 }
01856 
01857                 for(i = 0; i < namerec->data.num_ips; i++) {
01858                         set_nb_flags(&prdata[i*6],namerec->data.nb_flags);
01859                         putip((char *)&prdata[2+(i*6)], &namerec->data.ip[i]);
01860                 }
01861 
01862                 sort_query_replies(prdata, i, p->ip);
01863                 reply_data_len = namerec->data.num_ips * 6;
01864         }
01865 
01866         reply_netbios_packet(p,                                /* Packet to reply to. */
01867                                 rcode,                         /* Result code. */
01868                                 WINS_QUERY,                    /* nmbd type code. */
01869                                 NMB_NAME_QUERY_OPCODE,         /* opcode. */
01870                                 ttl,                           /* ttl. */
01871                                 prdata,                        /* data to send. */
01872                                 reply_data_len);               /* data length. */
01873 
01874         if(prdata != rdata) {
01875                 SAFE_FREE(prdata);
01876         }
01877 }
01878 
01879 /***********************************************************************
01880  Deal with a name query.
01881 ***********************************************************************/
01882 
01883 void wins_process_name_query_request(struct subnet_record *subrec, 
01884                                      struct packet_struct *p)
01885 {
01886         struct nmb_packet *nmb = &p->packet.nmb;
01887         struct nmb_name *question = &nmb->question.question_name;
01888         struct name_record *namerec = NULL;
01889         unstring qname;
01890 
01891         DEBUG(3,("wins_process_name_query: name query for name %s from IP %s\n", 
01892                 nmb_namestr(question), inet_ntoa(p->ip) ));
01893 
01894         /*
01895          * Special name code. If the queried name is *<1b> then search
01896          * the entire WINS database and return a list of all the IP addresses
01897          * registered to any <1b> name. This is to allow domain master browsers
01898          * to discover other domains that may not have a presence on their subnet.
01899          */
01900 
01901         pull_ascii_nstring(qname, sizeof(qname), question->name);
01902         if(strequal( qname, "*") && (question->name_type == 0x1b)) {
01903                 process_wins_dmb_query_request( subrec, p);
01904                 return;
01905         }
01906 
01907         namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
01908 
01909         if(namerec != NULL) {
01910                 /*
01911                  * If the name is not anymore in active state then reply not found.
01912                  * it's fair even if we keep it in the cache for days.
01913                  */
01914                 if (!WINS_STATE_ACTIVE(namerec)) {
01915                         DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n",
01916                                 nmb_namestr(question) ));
01917                         send_wins_name_query_response(NAM_ERR, p, namerec);
01918                         return;
01919                 }
01920 
01921                 /* 
01922                  * If it's a DNSFAIL_NAME then reply name not found.
01923                  */
01924 
01925                 if( namerec->data.source == DNSFAIL_NAME ) {
01926                         DEBUG(3,("wins_process_name_query: name query for name %s returning DNS fail.\n",
01927                                 nmb_namestr(question) ));
01928                         send_wins_name_query_response(NAM_ERR, p, namerec);
01929                         return;
01930                 }
01931 
01932                 /*
01933                  * If the name has expired then reply name not found.
01934                  */
01935 
01936                 if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < p->timestamp) ) {
01937                         DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n",
01938                                         nmb_namestr(question) ));
01939                         send_wins_name_query_response(NAM_ERR, p, namerec);
01940                         return;
01941                 }
01942 
01943                 DEBUG(3,("wins_process_name_query: name query for name %s returning first IP %s.\n",
01944                                 nmb_namestr(question), inet_ntoa(namerec->data.ip[0]) ));
01945 
01946                 send_wins_name_query_response(0, p, namerec);
01947                 return;
01948         }
01949 
01950         /* 
01951          * Name not found in WINS - try a dns query if it's a 0x20 name.
01952          */
01953 
01954         if(lp_dns_proxy() && ((question->name_type == 0x20) || question->name_type == 0)) {
01955                 DEBUG(3,("wins_process_name_query: name query for name %s not found - doing dns lookup.\n",
01956                                 nmb_namestr(question) ));
01957 
01958                 queue_dns_query(p, question);
01959                 return;
01960         }
01961 
01962         /*
01963          * Name not found - return error.
01964          */
01965 
01966         send_wins_name_query_response(NAM_ERR, p, NULL);
01967 }
01968 
01969 /****************************************************************************
01970 Send a WINS name release response.
01971 **************************************************************************/
01972 
01973 static void send_wins_name_release_response(int rcode, struct packet_struct *p)
01974 {
01975         struct nmb_packet *nmb = &p->packet.nmb;
01976         char rdata[6];
01977 
01978         memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
01979 
01980         reply_netbios_packet(p,                               /* Packet to reply to. */
01981                                 rcode,                        /* Result code. */
01982                                 NMB_REL,                      /* nmbd type code. */
01983                                 NMB_NAME_RELEASE_OPCODE,      /* opcode. */
01984                                 0,                            /* ttl. */
01985                                 rdata,                        /* data to send. */
01986                                 6);                           /* data length. */
01987 }
01988 
01989 /***********************************************************************
01990  Deal with a name release.
01991 ***********************************************************************/
01992 
01993 void wins_process_name_release_request(struct subnet_record *subrec,
01994                                        struct packet_struct *p)
01995 {
01996         struct nmb_packet *nmb = &p->packet.nmb;
01997         struct nmb_name *question = &nmb->question.question_name;
01998         BOOL bcast = nmb->header.nm_flags.bcast;
01999         uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
02000         struct name_record *namerec = NULL;
02001         struct in_addr from_ip;
02002         BOOL releasing_group_name = (nb_flags & NB_GROUP) ? True : False;;
02003 
02004         putip((char *)&from_ip,&nmb->additional->rdata[2]);
02005 
02006         if(bcast) {
02007                 /*
02008                  * We should only get unicast name registration packets here.
02009                  * Anyone trying to register broadcast should not be going to a WINS
02010                  * server. Log an error here.
02011                  */
02012 
02013                 DEBUG(0,("wins_process_name_release_request: broadcast name registration request \
02014 received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n",
02015                         nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
02016                 return;
02017         }
02018   
02019         DEBUG(3,("wins_process_name_release_request: %s name release for name %s \
02020 IP %s\n", releasing_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) ));
02021     
02022         /*
02023          * Deal with policy regarding 0x1d names.
02024          */
02025 
02026         if(!releasing_group_name && (question->name_type == 0x1d)) {
02027                 DEBUG(3,("wins_process_name_release_request: Ignoring request \
02028 to release name %s from IP %s.", nmb_namestr(question), inet_ntoa(p->ip) ));
02029                 send_wins_name_release_response(0, p);
02030                 return;
02031         }
02032 
02033         /*
02034          * See if the name already exists.
02035          */
02036     
02037         namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
02038 
02039         if( (namerec == NULL) || ((namerec != NULL) && (namerec->data.source != REGISTER_NAME)) ) {
02040                 send_wins_name_release_response(NAM_ERR, p);
02041                 return;
02042         }
02043 
02044         /* 
02045          * Check that the sending machine has permission to release this name.
02046          * If it's a group name not ending in 0x1c then just say yes and let
02047          * the group time out.
02048          */
02049 
02050         if(releasing_group_name && (question->name_type != 0x1c)) {
02051                 send_wins_name_release_response(0, p);
02052                 return;
02053         }
02054 
02055         /* 
02056          * Check that the releasing node is on the list of IP addresses
02057          * for this name. Disallow the release if not.
02058          */
02059 
02060         if(!find_ip_in_name_record(namerec, from_ip)) {
02061                 DEBUG(3,("wins_process_name_release_request: Refusing request to \
02062 release name %s as IP %s is not one of the known IP's for this name.\n",
02063                         nmb_namestr(question), inet_ntoa(from_ip) ));
02064                 send_wins_name_release_response(NAM_ERR, p);
02065                 return;
02066         }
02067 
02068         /*
02069          * Check if the record is active. IF it's already released
02070          * or tombstoned, refuse the release.
02071          */
02072 
02073         if (!WINS_STATE_ACTIVE(namerec)) {
02074                 DEBUG(3,("wins_process_name_release_request: Refusing request to \
02075 release name %s as this record is not active anymore.\n", nmb_namestr(question) ));
02076                 send_wins_name_release_response(NAM_ERR, p);
02077                 return;
02078         }    
02079 
02080         /*
02081          * Check if the record is a 0x1c group
02082          * and has more then one ip
02083          * remove only this address.
02084          */
02085 
02086         if(releasing_group_name && (question->name_type == 0x1c) && (namerec->data.num_ips > 1)) {
02087                 remove_ip_from_name_record(namerec, from_ip);
02088                 DEBUG(3,("wins_process_name_release_request: Remove IP %s from NAME: %s\n",
02089                                 inet_ntoa(from_ip),nmb_namestr(question)));
02090                 wins_hook("delete", namerec, 0);
02091                 send_wins_name_release_response(0, p);
02092                 return;
02093         }
02094 
02095         /* 
02096          * Send a release response.
02097          * Flag the name as released and update the ttl
02098          */
02099 
02100         namerec->data.wins_flags |= WINS_RELEASED;
02101         update_name_ttl(namerec, EXTINCTION_INTERVAL);
02102 
02103         wins_hook("delete", namerec, 0);
02104         send_wins_name_release_response(0, p);
02105 }
02106 
02107 /*******************************************************************
02108  WINS time dependent processing.
02109 ******************************************************************/
02110 
02111 static int wins_processing_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
02112 {
02113         time_t t = *(time_t *)state;
02114         BOOL store_record = False;
02115         struct name_record *namerec = NULL;
02116         struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0");
02117 
02118         if (kbuf.dsize != sizeof(unstring) + 1) {
02119                 return 0;
02120         }
02121 
02122         namerec = wins_record_to_name_record(kbuf, dbuf);
02123         if (!namerec) {
02124                 return 0;
02125         }
02126 
02127         if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < t) ) {
02128                 if( namerec->data.source == SELF_NAME ) {
02129                         DEBUG( 3, ( "wins_processing_traverse_fn: Subnet %s not expiring SELF name %s\n", 
02130                                    wins_server_subnet->subnet_name, nmb_namestr(&namerec->name) ) );
02131                         namerec->data.death_time += 300;
02132                         store_record = True;
02133                         goto done;
02134                 } else if (namerec->data.source == DNS_NAME || namerec->data.source == DNSFAIL_NAME) {
02135                         DEBUG(3,("wins_processing_traverse_fn: deleting timed out DNS name %s\n",
02136                                         nmb_namestr(&namerec->name)));
02137                         remove_name_from_wins_namelist(namerec );
02138                         goto done;
02139                 }
02140 
02141                 /* handle records, samba is the wins owner */
02142                 if (ip_equal(namerec->data.wins_ip, our_fake_ip)) {
02143                         switch (namerec->data.wins_flags & WINS_STATE_MASK) {
02144                                 case WINS_ACTIVE:
02145                                         namerec->data.wins_flags&=~WINS_STATE_MASK;
02146                                         namerec->data.wins_flags|=WINS_RELEASED;
02147                                         namerec->data.death_time = t + EXTINCTION_INTERVAL;
02148                                         DEBUG(3,("wins_processing_traverse_fn: expiring %s\n",
02149                                                 nmb_namestr(&namerec->name)));
02150                                         store_record = True;
02151                                         goto done;
02152                                 case WINS_RELEASED:
02153                                         namerec->data.wins_flags&=~WINS_STATE_MASK;
02154                                         namerec->data.wins_flags|=WINS_TOMBSTONED;
02155                                         namerec->data.death_time = t + EXTINCTION_TIMEOUT;
02156                                         get_global_id_and_update(&namerec->data.id, True);
02157                                         DEBUG(3,("wins_processing_traverse_fn: tombstoning %s\n",
02158                                                 nmb_namestr(&namerec->name)));
02159                                         store_record = True;
02160                                         goto done;
02161                                 case WINS_TOMBSTONED:
02162                                         DEBUG(3,("wins_processing_traverse_fn: deleting %s\n",
02163                                                 nmb_namestr(&namerec->name)));
02164                                         remove_name_from_wins_namelist(namerec );
02165                                         goto done;
02166                         }
02167                 } else {
02168                         switch (namerec->data.wins_flags & WINS_STATE_MASK) {
02169                                 case WINS_ACTIVE:
02170                                         /* that's not as MS says it should be */
02171                                         namerec->data.wins_flags&=~WINS_STATE_MASK;
02172                                         namerec->data.wins_flags|=WINS_TOMBSTONED;
02173                                         namerec->data.death_time = t + EXTINCTION_TIMEOUT;
02174                                         DEBUG(3,("wins_processing_traverse_fn: tombstoning %s\n",
02175                                                 nmb_namestr(&namerec->name)));
02176                                         store_record = True;
02177                                         goto done;
02178                                 case WINS_TOMBSTONED:
02179                                         DEBUG(3,("wins_processing_traverse_fn: deleting %s\n",
02180                                                 nmb_namestr(&namerec->name)));
02181                                         remove_name_from_wins_namelist(namerec );
02182                                         goto done;
02183                                 case WINS_RELEASED:
02184                                         DEBUG(0,("wins_processing_traverse_fn: %s is in released state and\
02185 we are not the wins owner !\n", nmb_namestr(&namerec->name)));
02186                                         goto done;
02187                         }
02188                 }
02189         }
02190 
02191   done:
02192 
02193         if (store_record) {
02194                 wins_store_changed_namerec(namerec);
02195         }
02196 
02197         SAFE_FREE(namerec->data.ip);
02198         SAFE_FREE(namerec);
02199 
02200         return 0;
02201 }
02202 
02203 /*******************************************************************
02204  Time dependent wins processing.
02205 ******************************************************************/
02206 
02207 void initiate_wins_processing(time_t t)
02208 {
02209         static time_t lasttime = 0;
02210 
02211         if (!lasttime) {
02212                 lasttime = t;
02213         }
02214         if (t - lasttime < 20) {
02215                 return;
02216         }
02217 
02218         if(!lp_we_are_a_wins_server()) {
02219                 lasttime = t;
02220                 return;
02221         }
02222 
02223         tdb_traverse(wins_tdb, wins_processing_traverse_fn, &t);
02224 
02225         wins_delete_all_tmp_in_memory_records();
02226 
02227         wins_write_database(t, True);
02228 
02229         lasttime = t;
02230 }
02231 
02232 /*******************************************************************
02233  Write out one record.
02234 ******************************************************************/
02235 
02236 void wins_write_name_record(struct name_record *namerec, XFILE *fp)
02237 {
02238         int i;
02239         struct tm *tm;
02240 
02241         DEBUGADD(4,("%-19s ", nmb_namestr(&namerec->name) ));
02242 
02243         if( namerec->data.death_time != PERMANENT_TTL ) {
02244                 char *ts, *nl;
02245 
02246                 tm = localtime(&namerec->data.death_time);
02247                 if (!tm) {
02248                         return;
02249                 }
02250                 ts = asctime(tm);
02251                 if (!ts) {
02252                         return;
02253                 }
02254                 nl = strrchr( ts, '\n' );
02255                 if( NULL != nl ) {
02256                         *nl = '\0';
02257                 }
02258                 DEBUGADD(4,("TTL = %s  ", ts ));
02259         } else {
02260                 DEBUGADD(4,("TTL = PERMANENT                 "));
02261         }
02262 
02263         for (i = 0; i < namerec->data.num_ips; i++) {
02264                 DEBUGADD(4,("%15s ", inet_ntoa(namerec->data.ip[i]) ));
02265         }
02266         DEBUGADD(4,("%2x\n", namerec->data.nb_flags ));
02267 
02268         if( namerec->data.source == REGISTER_NAME ) {
02269                 unstring name;
02270                 pull_ascii_nstring(name, sizeof(name), namerec->name.name);
02271                 x_fprintf(fp, "\"%s#%02x\" %d ", name,namerec->name.name_type, /* Ignore scope. */
02272                         (int)namerec->data.death_time);
02273 
02274                 for (i = 0; i < namerec->data.num_ips; i++)
02275                         x_fprintf( fp, "%s ", inet_ntoa( namerec->data.ip[i] ) );
02276                 x_fprintf( fp, "%2xR\n", namerec->data.nb_flags );
02277         }
02278 }
02279 
02280 /*******************************************************************
02281  Write out the current WINS database.
02282 ******************************************************************/
02283 
02284 static int wins_writedb_traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
02285 {
02286         struct name_record *namerec = NULL;
02287         XFILE *fp = (XFILE *)state;
02288 
02289         if (kbuf.dsize != sizeof(unstring) + 1) {
02290                 return 0;
02291         }
02292 
02293         namerec = wins_record_to_name_record(kbuf, dbuf);
02294         if (!namerec) {
02295                 return 0;
02296         }
02297 
02298         wins_write_name_record(namerec, fp);
02299 
02300         SAFE_FREE(namerec->data.ip);
02301         SAFE_FREE(namerec);
02302         return 0;
02303 }
02304 
02305 
02306 void wins_write_database(time_t t, BOOL background)
02307 {
02308         static time_t last_write_time = 0;
02309         pstring fname, fnamenew;
02310 
02311         XFILE *fp;
02312    
02313         if (background) {
02314                 if (!last_write_time) {
02315                         last_write_time = t;
02316                 }
02317                 if (t - last_write_time < 120) {
02318                         return;
02319                 }
02320 
02321         }
02322 
02323         if(!lp_we_are_a_wins_server()) {
02324                 return;
02325         }
02326 
02327         /* We will do the writing in a child process to ensure that the parent doesn't block while this is done */
02328         if (background) {
02329                 CatchChild();
02330                 if (sys_fork()) {
02331                         return;
02332                 }
02333                 if (tdb_reopen(wins_tdb)) {
02334                         DEBUG(0,("wins_write_database: tdb_reopen failed. Error was %s\n",
02335                                 strerror(errno)));
02336                         _exit(0);
02337                         return;
02338                 }
02339         }
02340 
02341         slprintf(fname,sizeof(fname)-1,"%s/%s", lp_lockdir(), WINS_LIST);
02342         all_string_sub(fname,"//", "/", 0);
02343         slprintf(fnamenew,sizeof(fnamenew)-1,"%s.%u", fname, (unsigned int)sys_getpid());
02344 
02345         if((fp = x_fopen(fnamenew,O_WRONLY|O_CREAT,0644)) == NULL) {
02346                 DEBUG(0,("wins_write_database: Can't open %s. Error was %s\n", fnamenew, strerror(errno)));
02347                 if (background) {
02348                         _exit(0);
02349                 }
02350                 return;
02351         }
02352 
02353         DEBUG(4,("wins_write_database: Dump of WINS name list.\n"));
02354 
02355         x_fprintf(fp,"VERSION %d %u\n", WINS_VERSION, 0);
02356  
02357         tdb_traverse(wins_tdb, wins_writedb_traverse_fn, fp);
02358 
02359         x_fclose(fp);
02360         chmod(fnamenew,0644);
02361         unlink(fname);
02362         rename(fnamenew,fname);
02363         if (background) {
02364                 _exit(0);
02365         }
02366 }
02367 
02368 #if 0
02369         Until winsrepl is done.
02370 /****************************************************************************
02371  Process a internal Samba message receiving a wins record.
02372 ***************************************************************************/
02373 
02374 void nmbd_wins_new_entry(int msg_type, struct process_id src,
02375                          void *buf, size_t len, void *private_data)
02376 {
02377         WINS_RECORD *record;
02378         struct name_record *namerec = NULL;
02379         struct name_record *new_namerec = NULL;
02380         struct nmb_name question;
02381         BOOL overwrite=False;
02382         struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0");
02383         int i;
02384 
02385         if (buf==NULL) {
02386                 return;
02387         }
02388         
02389         /* Record should use UNIX codepage. Ensure this is so in the wrepld code. JRA. */
02390         record=(WINS_RECORD *)buf;
02391         
02392         make_nmb_name(&question, record->name, record->type);
02393 
02394         namerec = find_name_on_subnet(wins_server_subnet, &question, FIND_ANY_NAME);
02395 
02396         /* record doesn't exist, add it */
02397         if (namerec == NULL) {
02398                 DEBUG(3,("nmbd_wins_new_entry: adding new replicated record: %s<%02x> for wins server: %s\n", 
02399                           record->name, record->type, inet_ntoa(record->wins_ip)));
02400 
02401                 new_namerec=add_name_to_subnet( wins_server_subnet,
02402                                                 record->name,
02403                                                 record->type,
02404                                                 record->nb_flags, 
02405                                                 EXTINCTION_INTERVAL,
02406                                                 REGISTER_NAME,
02407                                                 record->num_ips,
02408                                                 record->ip);
02409 
02410                 if (new_namerec!=NULL) {
02411                                 update_wins_owner(new_namerec, record->wins_ip);
02412                                 update_wins_flag(new_namerec, record->wins_flags);
02413                                 new_namerec->data.id=record->id;
02414 
02415                                 wins_server_subnet->namelist_changed = True;
02416                         }
02417         }
02418 
02419         /* check if we have a conflict */
02420         if (namerec != NULL) {
02421                 /* both records are UNIQUE */
02422                 if (namerec->data.wins_flags&WINS_UNIQUE && record->wins_flags&WINS_UNIQUE) {
02423 
02424                         /* the database record is a replica */
02425                         if (!ip_equal(namerec->data.wins_ip, our_fake_ip)) {
02426                                 if (namerec->data.wins_flags&WINS_ACTIVE && record->wins_flags&WINS_TOMBSTONED) {
02427                                         if (ip_equal(namerec->data.wins_ip, record->wins_ip))
02428                                                 overwrite=True;
02429                                 } else
02430                                         overwrite=True;
02431                         } else {
02432                         /* we are the wins owner of the database record */
02433                                 /* the 2 records have the same IP address */
02434                                 if (ip_equal(namerec->data.ip[0], record->ip[0])) {
02435                                         if (namerec->data.wins_flags&WINS_ACTIVE && record->wins_flags&WINS_TOMBSTONED)
02436                                                 get_global_id_and_update(&namerec->data.id, True);
02437                                         else
02438                                                 overwrite=True;
02439                                 
02440                                 } else {
02441                                 /* the 2 records have different IP address */
02442                                         if (namerec->data.wins_flags&WINS_ACTIVE) {
02443                                                 if (record->wins_flags&WINS_TOMBSTONED)
02444                                                         get_global_id_and_update(&namerec->data.id, True);
02445                                                 if (record->wins_flags&WINS_ACTIVE)
02446                                                         /* send conflict challenge to the replica node */
02447                                                         ;
02448                                         } else
02449                                                 overwrite=True;
02450                                 }
02451 
02452                         }
02453                 }
02454                 
02455                 /* the replica is a standard group */
02456                 if (record->wins_flags&WINS_NGROUP || record->wins_flags&WINS_SGROUP) {
02457                         /* if the database record is unique and active force a name release */
02458                         if (namerec->data.wins_flags&WINS_UNIQUE)
02459                                 /* send a release name to the unique node */
02460                                 ;
02461                         overwrite=True;
02462                 
02463                 }
02464         
02465                 /* the replica is a special group */
02466                 if (record->wins_flags&WINS_SGROUP && namerec->data.wins_flags&WINS_SGROUP) {
02467                         if (namerec->data.wins_flags&WINS_ACTIVE) {
02468                                 for (i=0; i<record->num_ips; i++)
02469                                         if(!find_ip_in_name_record(namerec, record->ip[i]))
02470                                                 add_ip_to_name_record(namerec, record->ip[i]);
02471                         } else {
02472                                 overwrite=True;
02473                         }
02474                 }
02475                 
02476                 /* the replica is a multihomed host */
02477                 
02478                 /* I'm giving up on multi homed. Too much complex to understand */
02479                 
02480                 if (record->wins_flags&WINS_MHOMED) {
02481                         if (! (namerec->data.wins_flags&WINS_ACTIVE)) {
02482                                 if ( !(namerec->data.wins_flags&WINS_RELEASED) && !(namerec->data.wins_flags&WINS_NGROUP))
02483                                         overwrite=True;
02484                         }
02485                         else {
02486                                 if (ip_equal(record->wins_ip, namerec->data.wins_ip))
02487                                         overwrite=True;
02488                                 
02489                                 if (ip_equal(namerec->data.wins_ip, our_fake_ip))
02490                                         if (namerec->data.wins_flags&WINS_UNIQUE)
02491                                                 get_global_id_and_update(&namerec->data.id, True);
02492                                 
02493                         }
02494                         
02495                         if (record->wins_flags&WINS_ACTIVE && namerec->data.wins_flags&WINS_ACTIVE)
02496                                 if (namerec->data.wins_flags&WINS_UNIQUE ||
02497                                     namerec->data.wins_flags&WINS_MHOMED)
02498                                         if (ip_equal(record->wins_ip, namerec->data.wins_ip))
02499                                                 overwrite=True;
02500                                 
02501                 }
02502 
02503                 if (overwrite == False)
02504                         DEBUG(3, ("nmbd_wins_new_entry: conflict in adding record: %s<%02x> from wins server: %s\n", 
02505                                   record->name, record->type, inet_ntoa(record->wins_ip)));
02506                 else {
02507                         DEBUG(3, ("nmbd_wins_new_entry: replacing record: %s<%02x> from wins server: %s\n", 
02508                                   record->name, record->type, inet_ntoa(record->wins_ip)));
02509 
02510                         /* remove the old record and add a new one */
02511                         remove_name_from_namelist( wins_server_subnet, namerec );
02512                         new_namerec=add_name_to_subnet( wins_server_subnet, record->name, record->type, record->nb_flags, 
02513                                                 EXTINCTION_INTERVAL, REGISTER_NAME, record->num_ips, record->ip);
02514                         if (new_namerec!=NULL) {
02515                                 update_wins_owner(new_namerec, record->wins_ip);
02516                                 update_wins_flag(new_namerec, record->wins_flags);
02517                                 new_namerec->data.id=record->id;
02518 
02519                                 wins_server_subnet->namelist_changed = True;
02520                         }
02521 
02522                         wins_server_subnet->namelist_changed = True;
02523                 }
02524 
02525         }
02526 }
02527 #endif

Sambaに対してSat Aug 29 21:23:08 2009に生成されました。  doxygen 1.4.7