nmbd_winsserver.c
来自「samba-3.0.22.tar.gz 编译smb服务器的源码」· C语言 代码 · 共 2,043 行 · 第 1/5 页
C
2,043 行
rdata[0] = (nmb->header.opcode & 0xF) << 3; if (nmb->header.nm_flags.authoritative && nmb->header.response) { rdata[0] |= 0x4; } if (nmb->header.nm_flags.trunc) { rdata[0] |= 0x2; } if (nmb->header.nm_flags.recursion_desired) { rdata[0] |= 0x1; } if (nmb->header.nm_flags.recursion_available && nmb->header.response) { rdata[1] |= 0x80; } if (nmb->header.nm_flags.bcast) { rdata[1] |= 0x10; } reply_netbios_packet(p, /* Packet to reply to. */ 0, /* Result code. */ NMB_WAIT_ACK, /* nmbd type code. */ NMB_WACK_OPCODE, /* opcode. */ ttl, /* ttl. */ (char *)rdata, /* data to send. */ 2); /* data length. */}/****************************************************************************Send a WINS name registration response.**************************************************************************/static void send_wins_name_registration_response(int rcode, int ttl, struct packet_struct *p){ struct nmb_packet *nmb = &p->packet.nmb; char rdata[6]; memcpy(&rdata[0], &nmb->additional->rdata[0], 6); reply_netbios_packet(p, /* Packet to reply to. */ rcode, /* Result code. */ WINS_REG, /* nmbd type code. */ NMB_NAME_REG_OPCODE, /* opcode. */ ttl, /* ttl. */ rdata, /* data to send. */ 6); /* data length. */}/*********************************************************************** Deal with a name refresh request to a WINS server.************************************************************************/void wins_process_name_refresh_request( struct subnet_record *subrec, struct packet_struct *p ){ struct nmb_packet *nmb = &p->packet.nmb; struct nmb_name *question = &nmb->question.question_name; BOOL bcast = nmb->header.nm_flags.bcast; uint16 nb_flags = get_nb_flags(nmb->additional->rdata); BOOL group = (nb_flags & NB_GROUP) ? True : False; 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] ); if(bcast) { /* * We should only get unicast name refresh packets here. * Anyone trying to refresh broadcast should not be going * to a WINS server. Log an error here. */ if( DEBUGLVL( 0 ) ) { dbgtext( "wins_process_name_refresh_request: " ); dbgtext( "Broadcast name refresh request received " ); dbgtext( "for name %s ", nmb_namestr(question) ); dbgtext( "from IP %s ", inet_ntoa(from_ip) ); dbgtext( "on subnet %s. ", subrec->subnet_name ); dbgtext( "Error - Broadcasts should not be sent " ); dbgtext( "to a WINS server\n" ); } return; } if( DEBUGLVL( 3 ) ) { dbgtext( "wins_process_name_refresh_request: " ); dbgtext( "Name refresh for name %s IP %s\n", nmb_namestr(question), inet_ntoa(from_ip) ); } /* * See if the name already exists. * If not, handle it as a name registration and return. */ namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME); /* * If this is a refresh request and the name doesn't exist then * treat it like a registration request. This allows us to recover * from errors (tridge) */ if(namerec == NULL) { if( DEBUGLVL( 3 ) ) { dbgtext( "wins_process_name_refresh_request: " ); dbgtext( "Name refresh for name %s ", nmb_namestr( question ) ); dbgtext( "and the name does not exist. Treating " ); dbgtext( "as registration.\n" ); } wins_process_name_registration_request(subrec,p); return; } /* * if the name is present but not active, simply remove it * and treat the refresh request as a registration & return. */ if (namerec != NULL && !WINS_STATE_ACTIVE(namerec)) { if( DEBUGLVL( 5 ) ) { dbgtext( "wins_process_name_refresh_request: " ); dbgtext( "Name (%s) in WINS ", nmb_namestr(question) ); dbgtext( "was not active - removing it.\n" ); } 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. If not, refuse the refresh. * [crh: Why RFS_ERR instead of ACT_ERR? Is this what MS does?] */ if( (namerec != NULL) && ( (group && !NAME_GROUP(namerec)) || (!group && NAME_GROUP(namerec)) ) ) { if( DEBUGLVL( 3 ) ) { dbgtext( "wins_process_name_refresh_request: " ); dbgtext( "Name %s ", nmb_namestr(question) ); dbgtext( "group bit = %s does not match ", group ? "True" : "False" ); dbgtext( "group bit in WINS for this name.\n" ); } send_wins_name_registration_response(RFS_ERR, 0, p); return; } /* * For a unique name check that the person refreshing the name is * one of the registered IP addresses. If not - fail the refresh. * Do the same for group names with a type of 0x1c. * Just return success for unique 0x1d refreshes. For normal group * names update the ttl and return success. */ if( (!group || (group && (question->name_type == 0x1c))) && find_ip_in_name_record(namerec, from_ip) ) { /* * 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; } else if((group && (question->name_type == 0x1c))) { /* * Added by crh for bug #1079. * Fix from Bert Driehuis */ if( DEBUGLVL( 3 ) ) { dbgtext( "wins_process_name_refresh_request: " ); dbgtext( "Name refresh for name %s, ", nmb_namestr(question) ); dbgtext( "but IP address %s ", inet_ntoa(from_ip) ); dbgtext( "is not yet associated with " ); dbgtext( "that name. Treating as registration.\n" ); } wins_process_name_registration_request(subrec,p); return; } else if(group) { /* * Normal groups are all registered with an IP address of * 255.255.255.255 so we can't search for the IP address. */ update_name_ttl(namerec, ttl); wins_hook("refresh", namerec, ttl); send_wins_name_registration_response(0, ttl, p); return; } else if(!group && (question->name_type == 0x1d)) { /* * Special name type - just pretend the refresh succeeded. */ send_wins_name_registration_response(0, ttl, p); return; } else { /* * Fail the refresh. */ if( DEBUGLVL( 3 ) ) { dbgtext( "wins_process_name_refresh_request: " ); dbgtext( "Name refresh for name %s with IP %s ", nmb_namestr(question), inet_ntoa(from_ip) ); dbgtext( "and is IP is not known to the name.\n" ); } send_wins_name_registration_response(RFS_ERR, 0, p); return; }}/*********************************************************************** Deal with a name registration request query success to a client that owned the name. We have a locked pointer to the original packet stashed away in the userdata pointer. The success here is actually a failure as it means the client we queried wants to keep the name, so we must return a registration failure to the original requestor.************************************************************************/static void wins_register_query_success(struct subnet_record *subrec, struct userdata_struct *userdata, struct nmb_name *question_name, struct in_addr ip, struct res_rec *answers){ struct packet_struct *orig_reg_packet; memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *)); DEBUG(3,("wins_register_query_success: Original client at IP %s still wants the \name %s. Rejecting registration request.\n", inet_ntoa(ip), nmb_namestr(question_name) )); send_wins_name_registration_response(RFS_ERR, 0, orig_reg_packet); orig_reg_packet->locked = False; free_packet(orig_reg_packet);}/*********************************************************************** Deal with a name registration request query failure to a client that owned the name. We have a locked pointer to the original packet stashed away in the userdata pointer. The failure here is actually a success as it means the client we queried didn't want to keep the name, so we can remove the old name record and then successfully add the new name.************************************************************************/static void wins_register_query_fail(struct subnet_record *subrec, struct response_record *rrec, struct nmb_name *question_name, int rcode){ struct userdata_struct *userdata = rrec->userdata; struct packet_struct *orig_reg_packet; struct name_record *namerec = NULL; memcpy((char *)&orig_reg_packet, userdata->data, sizeof(struct packet_struct *)); /* * We want to just add the name, as we now know the original owner * didn't want it. But we can't just do that as an arbitary * amount of time may have taken place between the name query * request and this timeout/error response. So we check that * the name still exists and is in the same state - if so * we remove it and call wins_process_name_registration_request() * as we know it will do the right thing now. */ namerec = find_name_on_subnet(subrec, question_name, FIND_ANY_NAME); if ((namerec != NULL) && (namerec->data.source == REGISTER_NAME) && ip_equal(rrec->packet->ip, *namerec->data.ip)) { remove_name_from_namelist( subrec, namerec); namerec = NULL; } if(namerec == NULL) { wins_process_name_registration_request(subrec, orig_reg_packet); } else { DEBUG(2,("wins_register_query_fail: The state of the WINS database changed between " "querying for name %s in order to replace it and this reply.\n", nmb_namestr(question_name) )); } orig_reg_packet->locked = False; free_packet(orig_reg_packet);}/*********************************************************************** Deal with a name registration request to a WINS server. Use the following pseudocode : registering_group | | +--------name exists | | | | | +--- existing name is group | | | | | | | | +--- add name (return). | | | | | +--- exiting name is unique | | | | | +--- query existing owner (return). | | +--------name doesn't exist | | +--- add name (return). registering_unique | | +--------name exists | | | | | +--- existing name is group | | | | | | | | +--- fail add (return). | | | | | +--- exiting name is unique | | | | | +--- query existing owner (return). | | +--------name doesn't exist | | +--- add name (return). As can be seen from the above, the two cases may be collapsed onto each other with the exception of the case where the name already exists and is a group name. This case we handle with an if statement. ************************************************************************/void wins_process_name_registration_request(struct subnet_record *subrec, struct packet_struct *p){ unstring name; struct nmb_packet *nmb = &p->packet.nmb; struct nmb_name *question = &nmb->question.question_name; BOOL bcast = nmb->header.nm_flags.bcast; uint16 nb_flags = get_nb_flags(nmb->additional->rdata); int ttl = get_ttl_from_packet(nmb); 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]); if(bcast) { /* * We should only get unicast name registration packets here. * Anyone trying to register broadcast should not be going to a WINS * server. Log an error here. */ DEBUG(0,("wins_process_name_registration_request: broadcast name registration request \received for name %s from IP %s on subnet %s. Error - should not be sent to WINS server\n", nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name)); return; } DEBUG(3,("wins_process_name_registration_request: %s name registration for name %s \IP %s\n", registering_group_name ? "Group" : "Unique", nmb_namestr(question), inet_ntoa(from_ip) )); /* * See if the name already exists. */ 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.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?