diff options
Diffstat (limited to 'source/nmbd/nmbd_winsserver.c')
-rw-r--r-- | source/nmbd/nmbd_winsserver.c | 929 |
1 files changed, 291 insertions, 638 deletions
diff --git a/source/nmbd/nmbd_winsserver.c b/source/nmbd/nmbd_winsserver.c index 13554a9430b..45385fc4e00 100644 --- a/source/nmbd/nmbd_winsserver.c +++ b/source/nmbd/nmbd_winsserver.c @@ -1,5 +1,6 @@ /* - Unix SMB/CIFS implementation. + Unix SMB/Netbios implementation. + Version 1.9. NBT netbios routines and daemon - version 2 Copyright (C) Jeremy Allison 1994-1998 @@ -22,84 +23,13 @@ #include "includes.h" -#define WINS_LIST "wins.tdb" +#define WINS_LIST "wins.dat" #define WINS_VERSION 1 /**************************************************************************** -change the wins owner address in the record. -*****************************************************************************/ -static void update_wins_owner(struct name_record *namerec, struct in_addr wins_ip) -{ - if (namerec==NULL) - return; - namerec->data.wins_ip=wins_ip; -} - -/**************************************************************************** -create the wins flags based on the nb flags and the input value. -*****************************************************************************/ -static void update_wins_flag(struct name_record *namerec, int flags) -{ - if (namerec==NULL) - return; - - namerec->data.wins_flags=0x0; - - /* if it's a group, it can be a normal or a special one */ - if (namerec->data.nb_flags & NB_GROUP) { - if (namerec->name.name_type==0x1C) - namerec->data.wins_flags|=WINS_SGROUP; - else - if (namerec->data.num_ips>1) - namerec->data.wins_flags|=WINS_SGROUP; - else - namerec->data.wins_flags|=WINS_NGROUP; - } else { - /* can be unique or multi-homed */ - if (namerec->data.num_ips>1) - namerec->data.wins_flags|=WINS_MHOMED; - else - namerec->data.wins_flags|=WINS_UNIQUE; - } - - /* the node type are the same bits */ - namerec->data.wins_flags|=namerec->data.nb_flags&NB_NODETYPEMASK; - - /* the static bit is elsewhere */ - if (namerec->data.death_time == PERMANENT_TTL) - namerec->data.wins_flags|=WINS_STATIC; - - /* and add the given bits */ - namerec->data.wins_flags|=flags; - - DEBUG(8,("update_wins_flag: nbflags: 0x%x, ttl: 0x%d, flags: 0x%x, winsflags: 0x%x\n", - namerec->data.nb_flags, (int)namerec->data.death_time, flags, namerec->data.wins_flags)); - -} - -/**************************************************************************** -return the general ID value and increase it if requested -*****************************************************************************/ -static void get_global_id_and_update(SMB_BIG_UINT *current_id, BOOL update) -{ - /* - * it's kept as a static here, to prevent people from messing - * with the value directly - */ - - static SMB_BIG_UINT general_id = 1; - - DEBUG(5,("get_global_id_and_update: updating version ID: %d\n", (int)general_id)); - - *current_id = general_id; - - if (update) - general_id++; -} - -/**************************************************************************** possibly call the WINS hook external program when a WINS change is made *****************************************************************************/ + static void wins_hook(char *operation, struct name_record *namerec, int ttl) { pstring command; @@ -110,7 +40,7 @@ static void wins_hook(char *operation, struct name_record *namerec, int ttl) if (!cmd || !*cmd) return; for (p=namerec->name.name; *p; p++) { - if (!(isalnum((int)*p) || strchr_m("._-",*p))) { + if (!(isalnum((int)*p) || strchr("._-",*p))) { DEBUG(3,("not calling wins hook for invalid name %s\n", nmb_namestr(&namerec->name))); return; } @@ -134,6 +64,24 @@ static void wins_hook(char *operation, struct name_record *namerec, int ttl) /**************************************************************************** +hash our interfaces and netbios names settings +*****************************************************************************/ +static unsigned wins_hash(void) +{ + int i; + unsigned ret = iface_hash(); + extern char **my_netbios_names; + + for (i=0;my_netbios_names[i];i++) + ret ^= str_checksum(my_netbios_names[i]); + + ret ^= str_checksum(lp_workgroup()); + + return ret; +} + + +/**************************************************************************** Determine if this packet should be allocated to the WINS server. *****************************************************************************/ @@ -221,115 +169,178 @@ Load or create the WINS database. BOOL initialise_wins(void) { - time_t time_now = time(NULL); - TDB_CONTEXT *tdb; - TDB_DATA kbuf, dbuf, newkey; - struct name_record *namerec = NULL; - struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0"); + time_t time_now = time(NULL); + FILE *fp; + pstring line; - DEBUG(2,("initialise_wins: started\n")); + if(!lp_we_are_a_wins_server()) + return True; - if(!lp_we_are_a_wins_server()) - return True; + add_samba_names_to_subnet(wins_server_subnet); - add_samba_names_to_subnet(wins_server_subnet); + if((fp = sys_fopen(lock_path(WINS_LIST),"r")) == NULL) + { + DEBUG(2,("initialise_wins: Can't open wins database file %s. Error was %s\n", + WINS_LIST, strerror(errno) )); + return True; + } - tdb = tdb_open_log(lock_path(WINS_LIST), 0, TDB_DEFAULT, O_RDONLY, 0600); - if (!tdb) { - DEBUG(2,("initialise_wins: Can't open wins database file %s. Error was %s\n", WINS_LIST, strerror(errno) )); - return True; - } + while (!feof(fp)) + { + pstring name_str, ip_str, ttl_str, nb_flags_str; + unsigned int num_ips; + pstring name; + struct in_addr *ip_list; + int type = 0; + int nb_flags; + int ttl; + char *ptr; + char *p; + BOOL got_token; + BOOL was_ip; + int i; + unsigned hash; + int version; + + /* Read a line from the wins.dat file. Strips whitespace + from the beginning and end of the line. + */ + if (!fgets_slash(line,sizeof(pstring),fp)) + continue; + + if (*line == '#') + continue; + + if (strncmp(line,"VERSION ", 8) == 0) { + if (sscanf(line,"VERSION %d %u", &version, &hash) != 2 || + version != WINS_VERSION || + hash != wins_hash()) { + DEBUG(0,("Discarding invalid wins.dat file [%s]\n",line)); + fclose(fp); + return True; + } + continue; + } - if (tdb_fetch_int32(tdb, INFO_VERSION) != WINS_VERSION) { - DEBUG(0,("Discarding invalid wins.dat file\n")); - tdb_close(tdb); - return True; - } + ptr = line; - for (kbuf = tdb_firstkey(tdb); - kbuf.dptr; - newkey = tdb_nextkey(tdb, kbuf), safe_free(kbuf.dptr), kbuf=newkey) { - - pstring name_type, name, ip_str; - char *p; - int type = 0; - int nb_flags; - int ttl; - unsigned int num_ips; - int high, low; - struct in_addr wins_ip; - struct in_addr *ip_list; - int wins_flags; - int len,i; - - if (strncmp(kbuf.dptr, ENTRY_PREFIX, strlen(ENTRY_PREFIX)) != 0) - continue; - - dbuf = tdb_fetch(tdb, kbuf); - if (!dbuf.dptr) continue; - - fstrcpy(name_type, kbuf.dptr+strlen(ENTRY_PREFIX)); - - pstrcpy(name, name_type); - - if((p = strchr(name,'#')) != NULL) { - *p = 0; - sscanf(p+1,"%x",&type); - } + /* + * Now we handle multiple IP addresses per name we need + * to iterate over the line twice. The first time to + * determine how many IP addresses there are, the second + * time to actually parse them into the ip_list array. + */ - len = tdb_unpack(dbuf.dptr, dbuf.dsize, "dddfddd", - &nb_flags, &high, &low, - ip_str, &ttl, &num_ips, &wins_flags); + if (!next_token(&ptr,name_str,NULL,sizeof(name_str))) + { + DEBUG(0,("initialise_wins: Failed to parse name when parsing line %s\n", line )); + continue; + } - wins_ip=*interpret_addr2(ip_str); + if (!next_token(&ptr,ttl_str,NULL,sizeof(ttl_str))) + { + DEBUG(0,("initialise_wins: Failed to parse time to live when parsing line %s\n", line )); + continue; + } - /* Don't reload replica records */ - if (!ip_equal(wins_ip, our_fake_ip)) - continue; + /* + * Determine the number of IP addresses per line. + */ + num_ips = 0; + do + { + got_token = next_token(&ptr,ip_str,NULL,sizeof(ip_str)); + was_ip = False; - /* Don't reload released or tombstoned records */ - if ((wins_flags&WINS_STATE_MASK) != WINS_ACTIVE) - continue; + if(got_token && strchr(ip_str, '.')) + { + num_ips++; + was_ip = True; + } + } while( got_token && was_ip); - /* Allocate the space for the ip_list. */ - if((ip_list = (struct in_addr *)malloc( num_ips * sizeof(struct in_addr))) == NULL) { - DEBUG(0,("initialise_wins: Malloc fail !\n")); - return False; - } + if(num_ips == 0) + { + DEBUG(0,("initialise_wins: Missing IP address when parsing line %s\n", line )); + continue; + } - for (i = 0; i < num_ips; i++) { - len += tdb_unpack(dbuf.dptr+len, dbuf.dsize-len, "f", ip_str); - ip_list[i] = *interpret_addr2(ip_str); - } + if(!got_token) + { + DEBUG(0,("initialise_wins: Missing nb_flags when parsing line %s\n", line )); + continue; + } - /* add all entries that have 60 seconds or more to live */ - if ((ttl - 60) > time_now || ttl == PERMANENT_TTL) { - if(ttl != PERMANENT_TTL) - ttl -= time_now; + /* Allocate the space for the ip_list. */ + if((ip_list = (struct in_addr *)malloc( num_ips * sizeof(struct in_addr))) == NULL) + { + DEBUG(0,("initialise_wins: Malloc fail !\n")); + return False; + } + + /* Reset and re-parse the line. */ + ptr = line; + next_token(&ptr,name_str,NULL,sizeof(name_str)); + next_token(&ptr,ttl_str,NULL,sizeof(ttl_str)); + for(i = 0; i < num_ips; i++) + { + next_token(&ptr, ip_str, NULL, sizeof(ip_str)); + ip_list[i] = *interpret_addr2(ip_str); + } + next_token(&ptr,nb_flags_str,NULL, sizeof(nb_flags_str)); + + /* + * Deal with SELF or REGISTER name encoding. Default is REGISTER + * for compatibility with old nmbds. + */ + + if(nb_flags_str[strlen(nb_flags_str)-1] == 'S') + { + DEBUG(5,("initialise_wins: Ignoring SELF name %s\n", line)); + SAFE_FREE(ip_list); + continue; + } + + if(nb_flags_str[strlen(nb_flags_str)-1] == 'R') + nb_flags_str[strlen(nb_flags_str)-1] = '\0'; + + /* Netbios name. # divides the name from the type (hex): netbios#xx */ + pstrcpy(name,name_str); + + if((p = strchr(name,'#')) != NULL) + { + *p = 0; + sscanf(p+1,"%x",&type); + } + + /* Decode the netbios flags (hex) and the time-to-live (in seconds). */ + sscanf(nb_flags_str,"%x",&nb_flags); + sscanf(ttl_str,"%d",&ttl); + + /* add all entries that have 60 seconds or more to live */ + if ((ttl - 60) > time_now || ttl == PERMANENT_TTL) + { + if(ttl != PERMANENT_TTL) + ttl -= time_now; - DEBUG( 4, ("initialise_wins: add name: %s#%02x ttl = %d first IP %s flags = %2x\n", - name, type, ttl, inet_ntoa(ip_list[0]), nb_flags)); - - namerec=add_name_to_subnet( wins_server_subnet, name, type, nb_flags, - ttl, REGISTER_NAME, num_ips, ip_list); - if (namerec!=NULL) { - update_wins_owner(namerec, wins_ip); - update_wins_flag(namerec, wins_flags); - /* we don't reload the ID, on startup we restart at 1 */ - get_global_id_and_update(&namerec->data.id, True); - } - - } else { - DEBUG(4, ("initialise_wins: not adding name (ttl problem) %s#%02x ttl = %d first IP %s flags = %2x\n", - name, type, ttl, inet_ntoa(ip_list[0]), nb_flags)); - } + DEBUG( 4, ("initialise_wins: add name: %s#%02x ttl = %d first IP %s flags = %2x\n", + name, type, ttl, inet_ntoa(ip_list[0]), nb_flags)); - SAFE_FREE(ip_list); - } + (void)add_name_to_subnet( wins_server_subnet, name, type, nb_flags, + ttl, REGISTER_NAME, num_ips, ip_list ); + + } + else + { + DEBUG(4, ("initialise_wins: not adding name (ttl problem) %s#%02x ttl = %d first IP %s flags = %2x\n", + name, type, ttl, inet_ntoa(ip_list[0]), nb_flags)); + } + + SAFE_FREE(ip_list); + } - tdb_close(tdb); - DEBUG(2,("initialise_wins: done\n")); - return True; + fclose(fp); + return True; } /**************************************************************************** @@ -399,7 +410,6 @@ void wins_process_name_refresh_request(struct subnet_record *subrec, struct name_record *namerec = NULL; int ttl = get_ttl_from_packet(nmb); struct in_addr from_ip; - struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0"); putip((char *)&from_ip,&nmb->additional->rdata[2]); @@ -441,21 +451,6 @@ the name does not exist. Treating as registration.\n", nmb_namestr(question) )); } /* - * if the name is present but not active, - * simply remove it and treat the request - * as a registration - */ - if (namerec != NULL && !WINS_STATE_ACTIVE(namerec)) - { - DEBUG(5,("wins_process_name_refresh_request: Name (%s) in WINS was \ -not active - removing it.\n", nmb_namestr(question) )); - remove_name_from_namelist( subrec, namerec ); - namerec = NULL; - wins_process_name_registration_request(subrec,p); - return; - } - - /* * Check that the group bits for the refreshing name and the * name in our database match. */ @@ -481,16 +476,6 @@ does not match group bit in WINS for this name.\n", nmb_namestr(question), group * Update the ttl. */ update_name_ttl(namerec, ttl); - - /* - * if the record is a replica: - * we take ownership and update the version ID. - */ - if (!ip_equal(namerec->data.wins_ip, our_fake_ip)) { - update_wins_owner(namerec, our_fake_ip); - get_global_id_and_update(&namerec->data.id, True); - } - send_wins_name_registration_response(0, ttl, p); wins_hook("refresh", namerec, ttl); return; @@ -674,7 +659,6 @@ void wins_process_name_registration_request(struct subnet_record *subrec, struct name_record *namerec = NULL; struct in_addr from_ip; BOOL registering_group_name = (nb_flags & NB_GROUP) ? True : False; - struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0"); putip((char *)&from_ip,&nmb->additional->rdata[2]); @@ -702,18 +686,6 @@ IP %s\n", registering_group_name ? "Group" : "Unique", nmb_namestr(question), in namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME); /* - * if the record exists but NOT in active state, - * consider it dead. - */ - if ( (namerec != NULL) && !WINS_STATE_ACTIVE(namerec)) - { - DEBUG(5,("wins_process_name_registration_request: Name (%s) in WINS was \ -not active - removing it.\n", nmb_namestr(question) )); - remove_name_from_namelist( subrec, namerec ); - namerec = NULL; - } - - /* * Deal with the case where the name found was a dns entry. * Remove it as we now have a NetBIOS client registering the * name. @@ -788,22 +760,8 @@ to register name %s from IP %s.\n", nmb_namestr(question), inet_ntoa(p->ip) )); /* * Check the ip address is not already in the group. */ - if(!find_ip_in_name_record(namerec, from_ip)) { + if(!find_ip_in_name_record(namerec, from_ip)) add_ip_to_name_record(namerec, from_ip); - /* we need to update the record for replication */ - get_global_id_and_update(&namerec->data.id, True); - - /* - * if the record is a replica, we must change - * the wins owner to us to make the replication updates - * it on the other wins servers. - * And when the partner will receive this record, - * it will update its own record. - */ - - update_wins_owner(namerec, our_fake_ip); - - } update_name_ttl(namerec, ttl); send_wins_name_registration_response(0, ttl, p); return; @@ -813,8 +771,6 @@ to register name %s from IP %s.\n", nmb_namestr(question), inet_ntoa(p->ip) )); /* * If we are adding a unique name, the name exists in the WINS db * and is a group name then reject the registration. - * - * explanation: groups have a higher priority than unique names. */ DEBUG(3,("wins_process_name_registration_request: Attempt to register name %s. Name \ @@ -858,18 +814,13 @@ is one of our (WINS server) names. Denying registration.\n", nmb_namestr(questio /* * If the name exists and it is a unique registration and the registering IP - * is the same as the (single) already registered IP then just update the ttl. - * - * But not if the record is an active replica. IF it's a replica, it means it can be - * the same client which has moved and not yet expired. So we don't update - * the ttl in this case and go beyond to do a WACK and query the old client + * is the same as the the (single) already registered IP then just update the ttl. */ if( !registering_group_name && (namerec != NULL) && (namerec->data.num_ips == 1) - && ip_equal( namerec->data.ip[0], from_ip ) - && ip_equal(namerec->data.wins_ip, our_fake_ip) ) + && ip_equal( namerec->data.ip[0], from_ip ) ) { update_name_ttl( namerec, ttl ); send_wins_name_registration_response( 0, ttl, p ); @@ -930,12 +881,9 @@ is one of our (WINS server) names. Denying registration.\n", nmb_namestr(questio */ (void)add_name_to_subnet( subrec, question->name, question->name_type, - nb_flags, ttl, REGISTER_NAME, 1, &from_ip); + nb_flags, ttl, REGISTER_NAME, 1, &from_ip ); if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) { - get_global_id_and_update(&namerec->data.id, True); - update_wins_owner(namerec, our_fake_ip); - update_wins_flag(namerec, WINS_ACTIVE); - wins_hook("add", namerec, ttl); + wins_hook("add", namerec, ttl); } send_wins_name_registration_response(0, ttl, p); @@ -960,7 +908,6 @@ static void wins_multihomed_register_query_success(struct subnet_record *subrec, struct name_record *namerec = NULL; struct in_addr from_ip; int ttl; - struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0"); memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *)); @@ -980,10 +927,10 @@ static void wins_multihomed_register_query_success(struct subnet_record *subrec, namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME); - if( (namerec == NULL) || (namerec->data.source != REGISTER_NAME) || !WINS_STATE_ACTIVE(namerec) ) + if( (namerec == NULL) || (namerec->data.source != REGISTER_NAME) ) { DEBUG(3,("wins_multihomed_register_query_success: name %s is not in the correct state to add \ -a subsequent IP address.\n", nmb_namestr(question_name) )); +a subsequent IP addess.\n", nmb_namestr(question_name) )); send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet); orig_reg_packet->locked = False; @@ -994,10 +941,6 @@ a subsequent IP address.\n", nmb_namestr(question_name) )); if(!find_ip_in_name_record(namerec, from_ip)) add_ip_to_name_record(namerec, from_ip); - - get_global_id_and_update(&namerec->data.id, True); - update_wins_owner(namerec, our_fake_ip); - update_wins_flag(namerec, WINS_ACTIVE); update_name_ttl(namerec, ttl); send_wins_name_registration_response(0, ttl, orig_reg_packet); wins_hook("add", namerec, ttl); @@ -1048,8 +991,7 @@ void wins_process_multihomed_name_registration_request( struct subnet_record *su int ttl = get_ttl_from_packet(nmb); struct name_record *namerec = NULL; struct in_addr from_ip; - BOOL group = (nb_flags & NB_GROUP) ? True : False; - struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0"); + BOOL group = (nb_flags & NB_GROUP) ? True : False;; putip((char *)&from_ip,&nmb->additional->rdata[2]); @@ -1101,16 +1043,6 @@ to register name %s from IP %s.", nmb_namestr(question), inet_ntoa(p->ip) )); namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME); /* - * if the record exists but NOT in active state, - * consider it dead. - */ - if ((namerec != NULL) && !WINS_STATE_ACTIVE(namerec)) { - DEBUG(5,("wins_process_multihomed_name_registration_request: Name (%s) in WINS was not active - removing it.\n", nmb_namestr(question))); - remove_name_from_namelist(subrec, namerec); - namerec = NULL; - } - - /* * Deal with the case where the name found was a dns entry. * Remove it as we now have a NetBIOS client registering the * name. @@ -1141,10 +1073,10 @@ to register name %s. Name already exists in WINS with source type %d.\n", } /* - * Reject if the name exists and is a GROUP name and is active. + * Reject if the name exists and is a GROUP name. */ - if((namerec != NULL) && NAME_GROUP(namerec) && WINS_STATE_ACTIVE(namerec)) + if((namerec != NULL) && NAME_GROUP(namerec)) { DEBUG(3,("wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \ already exists in WINS as a GROUP name.\n", nmb_namestr(question) )); @@ -1176,13 +1108,9 @@ is one of our (WINS server) names. Denying registration.\n", nmb_namestr(questio { /* * It's one of our names and one of our IP's. Ensure the IP is in the record and - * update the ttl. Update the version ID to force replication. + * update the ttl. */ if(!find_ip_in_name_record(namerec, from_ip)) { - get_global_id_and_update(&namerec->data.id, True); - update_wins_owner(namerec, our_fake_ip); - update_wins_flag(namerec, WINS_ACTIVE); - add_ip_to_name_record(namerec, from_ip); wins_hook("add", namerec, ttl); } else { @@ -1196,23 +1124,13 @@ is one of our (WINS server) names. Denying registration.\n", nmb_namestr(questio } /* - * If the name exists and is active, check if the IP address is already registered + * If the name exists check if the IP address is already registered * to that name. If so then update the ttl and reply success. */ - if((namerec != NULL) && find_ip_in_name_record(namerec, from_ip) && WINS_STATE_ACTIVE(namerec)) + if((namerec != NULL) && find_ip_in_name_record(namerec, from_ip)) { update_name_ttl(namerec, ttl); - /* - * If it's a replica, we need to become the wins owner - * to force the replication - */ - if (!ip_equal(namerec->data.wins_ip, our_fake_ip)) { - get_global_id_and_update(&namerec->data.id, True); - update_wins_owner(namerec, our_fake_ip); - update_wins_flag(namerec, WINS_ACTIVE); - } - send_wins_name_registration_response(0, ttl, p); wins_hook("refresh", namerec, ttl); return; @@ -1275,12 +1193,9 @@ is one of our (WINS server) names. Denying registration.\n", nmb_namestr(questio */ (void)add_name_to_subnet( subrec, question->name, question->name_type, - nb_flags, ttl, REGISTER_NAME, 1, &from_ip); + nb_flags, ttl, REGISTER_NAME, 1, &from_ip ); if ((namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME))) { - get_global_id_and_update(&namerec->data.id, True); - update_wins_owner(namerec, our_fake_ip); - update_wins_flag(namerec, WINS_ACTIVE); wins_hook("add", namerec, ttl); } @@ -1299,7 +1214,7 @@ static void process_wins_dmb_query_request(struct subnet_record *subrec, int num_ips; /* - * Go through all the ACTIVE names in the WINS db looking for those + * Go through all the names in the WINS db looking for those * ending in <1b>. Use this to calculate the number of IP * addresses we need to return. */ @@ -1309,7 +1224,7 @@ static void process_wins_dmb_query_request(struct subnet_record *subrec, namerec; namerec = (struct name_record *)ubi_trNext( namerec ) ) { - if(WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b ) + if( namerec->name.name_type == 0x1b ) num_ips += namerec->data.num_ips; } @@ -1339,7 +1254,7 @@ static void process_wins_dmb_query_request(struct subnet_record *subrec, namerec; namerec = (struct name_record *)ubi_trNext( namerec ) ) { - if(WINS_STATE_ACTIVE(namerec) && namerec->name.name_type == 0x1b) + if(namerec->name.name_type == 0x1b) { int i; for(i = 0; i < namerec->data.num_ips; i++) @@ -1420,7 +1335,7 @@ void send_wins_name_query_response(int rcode, struct packet_struct *p, prdata, /* data to send. */ reply_data_len); /* data length. */ - if(prdata != rdata) + if((prdata != rdata) && (prdata != NULL)) SAFE_FREE(prdata); } @@ -1455,17 +1370,6 @@ void wins_process_name_query_request(struct subnet_record *subrec, if(namerec != NULL) { - /* - * If the name is not anymore in active state then reply not found. - * it's fair even if we keep it in the cache for days. - */ - if (!WINS_STATE_ACTIVE(namerec)) - { - DEBUG(3,("wins_process_name_query: name query for name %s - name expired. Returning fail.\n", - nmb_namestr(question) )); - send_wins_name_query_response(NAM_ERR, p, namerec); - return; - } /* * If it's a DNSFAIL_NAME then reply name not found. */ @@ -1625,29 +1529,21 @@ release name %s as IP %s is not one of the known IP's for this name.\n", return; } - /* - * Check if the record is active. IF it's already released - * or tombstoned, refuse the release. - */ - if (!WINS_STATE_ACTIVE(namerec)) { - DEBUG(3,("wins_process_name_release_request: Refusing request to \ -release name %s as this record is not anymore active.\n", - nmb_namestr(question) )); - send_wins_name_release_response(NAM_ERR, p); - return; - } - /* - * Send a release response. - * Flag the name as released and update the ttl + * Release the name and then remove the IP from the known list. */ send_wins_name_release_response(0, p); - - namerec->data.wins_flags |= WINS_RELEASED; - update_name_ttl(namerec, EXTINCTION_INTERVAL); + remove_ip_from_name_record(namerec, from_ip); wins_hook("delete", namerec, 0); + + /* + * Remove the name entirely if no IP addresses left. + */ + if (namerec->data.num_ips == 0) + remove_name_from_namelist(subrec, namerec); + } /******************************************************************* @@ -1656,84 +1552,24 @@ release name %s as this record is not anymore active.\n", void initiate_wins_processing(time_t t) { - static time_t lasttime = 0; - struct name_record *namerec; - struct name_record *next_namerec; - struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0"); - - if (!lasttime) - lasttime = t; - if (t - lasttime < 20) - return; - - lasttime = t; - - if(!lp_we_are_a_wins_server()) - return; - - for( namerec = (struct name_record *)ubi_trFirst( wins_server_subnet->namelist ); - namerec; - namerec = next_namerec ) { - next_namerec = (struct name_record *)ubi_trNext( namerec ); - - if( (namerec->data.death_time != PERMANENT_TTL) - && (namerec->data.death_time < t) ) { - - if( namerec->data.source == SELF_NAME ) { - DEBUG( 3, ( "expire_names_on_subnet: Subnet %s not expiring SELF name %s\n", - wins_server_subnet->subnet_name, nmb_namestr(&namerec->name) ) ); - namerec->data.death_time += 300; - namerec->subnet->namelist_changed = True; - continue; - } - - /* handle records, samba is the wins owner */ - if (ip_equal(namerec->data.wins_ip, our_fake_ip)) { - switch (namerec->data.wins_flags | WINS_STATE_MASK) { - case WINS_ACTIVE: - namerec->data.wins_flags&=~WINS_STATE_MASK; - namerec->data.wins_flags|=WINS_RELEASED; - namerec->data.death_time = t + EXTINCTION_INTERVAL; - DEBUG(3,("initiate_wins_processing: expiring %s\n", nmb_namestr(&namerec->name))); - break; - case WINS_RELEASED: - namerec->data.wins_flags&=~WINS_STATE_MASK; - namerec->data.wins_flags|=WINS_TOMBSTONED; - namerec->data.death_time = t + EXTINCTION_TIMEOUT; - get_global_id_and_update(&namerec->data.id, True); - DEBUG(3,("initiate_wins_processing: tombstoning %s\n", nmb_namestr(&namerec->name))); - break; - case WINS_TOMBSTONED: - DEBUG(3,("initiate_wins_processing: deleting %s\n", nmb_namestr(&namerec->name))); - remove_name_from_namelist( wins_server_subnet, namerec ); - break; - } - } else { - switch (namerec->data.wins_flags | WINS_STATE_MASK) { - case WINS_ACTIVE: - /* that's not as MS says it should be */ - namerec->data.wins_flags&=~WINS_STATE_MASK; - namerec->data.wins_flags|=WINS_TOMBSTONED; - namerec->data.death_time = t + EXTINCTION_TIMEOUT; - DEBUG(3,("initiate_wins_processing: tombstoning %s\n", nmb_namestr(&namerec->name))); - case WINS_TOMBSTONED: - DEBUG(3,("initiate_wins_processing: deleting %s\n", nmb_namestr(&namerec->name))); - remove_name_from_namelist( wins_server_subnet, namerec ); - break; - case WINS_RELEASED: - DEBUG(0,("initiate_wins_processing: %s is in released state and\ -we are not the wins owner !\n", nmb_namestr(&namerec->name))); - break; - } - } + static time_t lasttime = 0; - } - } + if (!lasttime) + lasttime = t; + if (t - lasttime < 20) + return; + + lasttime = t; + + if(!lp_we_are_a_wins_server()) + return; - if(wins_server_subnet->namelist_changed) - wins_write_database(True); + expire_names_on_subnet(wins_server_subnet, t); - wins_server_subnet->namelist_changed = False; + if(wins_server_subnet->namelist_changed) + wins_write_database(True); + + wins_server_subnet->namelist_changed = False; } /******************************************************************* @@ -1741,268 +1577,85 @@ we are not the wins owner !\n", nmb_namestr(&namerec->name))); ******************************************************************/ void wins_write_database(BOOL background) { - struct name_record *namerec; - pstring fname, fnamenew; - TDB_CONTEXT *tdb; - TDB_DATA kbuf, dbuf; - pstring key, buf; - int len; - int num_record=0; - SMB_BIG_UINT id; - - if(!lp_we_are_a_wins_server()) - return; - - /* we will do the writing in a child process to ensure that the parent - doesn't block while this is done */ - if (background) { - CatchChild(); - if (sys_fork()) { - return; - } - } - - slprintf(fname,sizeof(fname)-1,"%s/%s", lp_lockdir(), WINS_LIST); - all_string_sub(fname,"//", "/", 0); - slprintf(fnamenew,sizeof(fnamenew)-1,"%s.%u", fname, (unsigned int)sys_getpid()); - - tdb = tdb_open_log(fnamenew, 0, TDB_DEFAULT, O_RDWR|O_CREAT|O_TRUNC, 0644); - if (!tdb) { - DEBUG(0,("wins_write_database: Can't open %s. Error was %s\n", fnamenew, strerror(errno))); - if (background) - _exit(0); - return; - } - - DEBUG(3,("wins_write_database: Dump of WINS name list.\n")); - - tdb_store_int32(tdb, INFO_VERSION, WINS_VERSION); + struct name_record *namerec; + pstring fname, fnamenew; - for (namerec = (struct name_record *)ubi_trFirst( wins_server_subnet->namelist ); - namerec; - namerec = (struct name_record *)ubi_trNext( namerec ) ) { - - int i; - struct tm *tm; - - DEBUGADD(3,("%-19s ", nmb_namestr(&namerec->name) )); - - if( namerec->data.death_time != PERMANENT_TTL ) { - char *ts, *nl; - - tm = LocalTime(&namerec->data.death_time); - ts = asctime(tm); - nl = strrchr_m( ts, '\n' ); - if( NULL != nl ) - *nl = '\0'; - - DEBUGADD(3,("TTL = %s ", ts )); - } else - DEBUGADD(3,("TTL = PERMANENT ")); - - for (i = 0; i < namerec->data.num_ips; i++) - DEBUGADD(0,("%15s ", inet_ntoa(namerec->data.ip[i]) )); - - DEBUGADD(3,("0x%2x 0x%2x %15s\n", namerec->data.nb_flags, namerec->data.wins_flags, inet_ntoa(namerec->data.wins_ip))); - - if( namerec->data.source == REGISTER_NAME ) { - - /* store the type in the key to make the name unique */ - slprintf(key, sizeof(key), "%s%s#%02x", ENTRY_PREFIX, namerec->name.name, namerec->name.name_type); - - len = tdb_pack(buf, sizeof(buf), "dddfddd", - (int)namerec->data.nb_flags, - (int)(namerec->data.id>>32), - (int)(namerec->data.id&0xffffffff), - inet_ntoa(namerec->data.wins_ip), - (int)namerec->data.death_time, - namerec->data.num_ips, - namerec->data.wins_flags); - - for (i = 0; i < namerec->data.num_ips; i++) - len += tdb_pack(buf+len, sizeof(buf)-len, "f", inet_ntoa(namerec->data.ip[i])); - - kbuf.dsize = strlen(key)+1; - kbuf.dptr = key; - dbuf.dsize = len; - dbuf.dptr = buf; - if (tdb_store(tdb, kbuf, dbuf, TDB_INSERT) != 0) return; - - num_record++; - } - } + FILE *fp; + + if(!lp_we_are_a_wins_server()) + return; - /* store the number of records */ - tdb_store_int32(tdb, INFO_COUNT, num_record); + /* we will do the writing in a child process to ensure that the parent + doesn't block while this is done */ + if (background) { + CatchChild(); + if (sys_fork()) { + return; + } + } - /* get and store the last used ID */ - get_global_id_and_update(&id, False); - tdb_store_int32(tdb, INFO_ID_HIGH, id>>32); - tdb_store_int32(tdb, INFO_ID_LOW, id&0xffffffff); + slprintf(fname,sizeof(fname)-1,"%s/%s", lp_lockdir(), WINS_LIST); + all_string_sub(fname,"//", "/", 0); + slprintf(fnamenew,sizeof(fnamenew)-1,"%s.%u", fname, (unsigned int)sys_getpid()); - tdb_close(tdb); + if((fp = sys_fopen(fnamenew,"w")) == NULL) + { + DEBUG(0,("wins_write_database: Can't open %s. Error was %s\n", fnamenew, strerror(errno))); + if (background) { + _exit(0); + } + return; + } - chmod(fnamenew,0644); - unlink(fname); - rename(fnamenew,fname); + DEBUG(4,("wins_write_database: Dump of WINS name list.\n")); - if (background) - _exit(0); -} + fprintf(fp,"VERSION %d %u\n", WINS_VERSION, wins_hash()); + + for( namerec + = (struct name_record *)ubi_trFirst( wins_server_subnet->namelist ); + namerec; + namerec = (struct name_record *)ubi_trNext( namerec ) ) + { + int i; + struct tm *tm; -/**************************************************************************** -process a internal Samba message receiving a wins record -***************************************************************************/ -void nmbd_wins_new_entry(int msg_type, pid_t src, void *buf, size_t len) -{ - WINS_RECORD *record; - struct name_record *namerec = NULL; - struct name_record *new_namerec = NULL; - struct nmb_name question; - BOOL overwrite=False; - struct in_addr our_fake_ip = *interpret_addr2("0.0.0.0"); - int i; + DEBUGADD(4,("%-19s ", nmb_namestr(&namerec->name) )); - if (buf==NULL) - return; - - record=(WINS_RECORD *)buf; - - ZERO_STRUCT(question); - memcpy(question.name, record->name, 16); - question.name_type=record->type; - - namerec = find_name_on_subnet(wins_server_subnet, &question, FIND_ANY_NAME); - - /* record doesn't exist, add it */ - if (namerec == NULL) { - DEBUG(3,("nmbd_wins_new_entry: adding new replicated record: %s<%02x> for wins server: %s\n", - record->name, record->type, inet_ntoa(record->wins_ip))); - - new_namerec=add_name_to_subnet( wins_server_subnet, record->name, record->type, record->nb_flags, - EXTINCTION_INTERVAL, REGISTER_NAME, record->num_ips, record->ip); - if (new_namerec!=NULL) { - update_wins_owner(new_namerec, record->wins_ip); - update_wins_flag(new_namerec, record->wins_flags); - new_namerec->data.id=record->id; - - wins_server_subnet->namelist_changed = True; - } - } + if( namerec->data.death_time != PERMANENT_TTL ) + { + char *ts, *nl; + + tm = LocalTime(&namerec->data.death_time); + ts = asctime(tm); + nl = strrchr( ts, '\n' ); + if( NULL != nl ) + *nl = '\0'; + DEBUGADD(4,("TTL = %s ", ts )); + } + else + DEBUGADD(4,("TTL = PERMANENT ")); - /* check if we have a conflict */ - if (namerec != NULL) { - /* both records are UNIQUE */ - if (namerec->data.wins_flags&WINS_UNIQUE && record->wins_flags&WINS_UNIQUE) { - - /* the database record is a replica */ - if (!ip_equal(namerec->data.wins_ip, our_fake_ip)) { - if (namerec->data.wins_flags&WINS_ACTIVE && record->wins_flags&WINS_TOMBSTONED) { - if (ip_equal(namerec->data.wins_ip, record->wins_ip)) - overwrite=True; - } else - overwrite=True; - } else { - /* we are the wins owner of the database record */ - /* the 2 records have the same IP address */ - if (ip_equal(namerec->data.ip[0], record->ip[0])) { - if (namerec->data.wins_flags&WINS_ACTIVE && record->wins_flags&WINS_TOMBSTONED) - get_global_id_and_update(&namerec->data.id, True); - else - overwrite=True; - - } else { - /* the 2 records have different IP address */ - if (namerec->data.wins_flags&WINS_ACTIVE) { - if (record->wins_flags&WINS_TOMBSTONED) - get_global_id_and_update(&namerec->data.id, True); - if (record->wins_flags&WINS_ACTIVE) - /* send conflict challenge to the replica node */ - ; - } else - overwrite=True; - } - - } - } - - /* the replica is a standard group */ - if (record->wins_flags&WINS_NGROUP || record->wins_flags&WINS_SGROUP) { - /* if the database record is unique and active force a name release */ - if (namerec->data.wins_flags&WINS_UNIQUE) - /* send a release name to the unique node */ - ; - overwrite=True; - - } - - /* the replica is a special group */ - if (record->wins_flags&WINS_SGROUP && namerec->data.wins_flags&WINS_SGROUP) { - if (namerec->data.wins_flags&WINS_ACTIVE) { - for (i=0; i<record->num_ips; i++) - if(!find_ip_in_name_record(namerec, record->ip[i])) - add_ip_to_name_record(namerec, record->ip[i]); - } - else - overwrite=True; - } - - /* the replica is a multihomed host */ - - /* I'm giving up on multi homed. Too much complex to understand */ - - if (record->wins_flags&WINS_MHOMED) { - if (! namerec->data.wins_flags&WINS_ACTIVE) { - if ( !namerec->data.wins_flags&WINS_RELEASED && !namerec->data.wins_flags&WINS_NGROUP) - overwrite=True; - } - else { - if (ip_equal(record->wins_ip, namerec->data.wins_ip)) - overwrite=True; - - if (ip_equal(namerec->data.wins_ip, our_fake_ip)) - if (namerec->data.wins_flags&WINS_UNIQUE) - get_global_id_and_update(&namerec->data.id, True); - - } - - if (record->wins_flags&WINS_ACTIVE && namerec->data.wins_flags&WINS_ACTIVE) - if (namerec->data.wins_flags&WINS_UNIQUE || - namerec->data.wins_flags&WINS_MHOMED) - if (ip_equal(record->wins_ip, namerec->data.wins_ip)) - overwrite=True; - - } + for (i = 0; i < namerec->data.num_ips; i++) + DEBUGADD(4,("%15s ", inet_ntoa(namerec->data.ip[i]) )); + DEBUGADD(4,("%2x\n", namerec->data.nb_flags )); - if (overwrite == False) - DEBUG(3, ("nmbd_wins_new_entry: conflict in adding record: %s<%02x> from wins server: %s\n", - record->name, record->type, inet_ntoa(record->wins_ip))); - else { - DEBUG(3, ("nmbd_wins_new_entry: replacing record: %s<%02x> from wins server: %s\n", - record->name, record->type, inet_ntoa(record->wins_ip))); - - /* remove the old record and add a new one */ - remove_name_from_namelist( wins_server_subnet, namerec ); - new_namerec=add_name_to_subnet( wins_server_subnet, record->name, record->type, record->nb_flags, - EXTINCTION_INTERVAL, REGISTER_NAME, record->num_ips, record->ip); - if (new_namerec!=NULL) { - update_wins_owner(new_namerec, record->wins_ip); - update_wins_flag(new_namerec, record->wins_flags); - new_namerec->data.id=record->id; - - wins_server_subnet->namelist_changed = True; - } - - wins_server_subnet->namelist_changed = True; - } + if( namerec->data.source == REGISTER_NAME ) + { + fprintf(fp, "\"%s#%02x\" %d ", + namerec->name.name,namerec->name.name_type, /* Ignore scope. */ + (int)namerec->data.death_time); - } + for (i = 0; i < namerec->data.num_ips; i++) + fprintf( fp, "%s ", inet_ntoa( namerec->data.ip[i] ) ); + fprintf( fp, "%2xR\n", namerec->data.nb_flags ); + } + } + + fclose(fp); + chmod(fnamenew,0644); + unlink(fname); + rename(fnamenew,fname); + if (background) { + _exit(0); + } } - - - - - - - - |