static void register_name_response(struct subnet_record *subrec, struct response_record *rrec, struct packet_struct *p) { /* * If we are registering broadcast, then getting a response is an * error - we do not have the name. If we are registering unicast, * then we expect to get a response. */ struct nmb_packet *nmb = &p->packet.nmb; BOOL bcast = nmb->header.nm_flags.bcast; BOOL success = True; struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name; struct nmb_name *answer_name = &nmb->answers->rr_name; int ttl = 0; uint16 nb_flags = 0; struct in_addr registered_ip; /* Sanity check. Ensure that the answer name in the incoming packet is the same as the requested name in the outgoing packet. */ if(!nmb_name_equal(question_name, answer_name)) { DEBUG(0,("register_name_response: Answer name %s differs from question \ name %s.\n", namestr(answer_name), namestr(question_name))); return; }
BOOL attempt_netbios_session_request(struct cli_state *cli, const char *srchost, const char *desthost, struct in_addr *pdest_ip) { struct nmb_name calling, called; make_nmb_name(&calling, srchost, 0x0); /* * If the called name is an IP address * then use *SMBSERVER immediately. */ if(is_ipaddress(desthost)) make_nmb_name(&called, "*SMBSERVER", 0x20); else make_nmb_name(&called, desthost, 0x20); if (!cli_session_request(cli, &calling, &called)) { struct nmb_name smbservername; make_nmb_name(&smbservername , "*SMBSERVER", 0x20); /* * If the name wasn't *SMBSERVER then * try with *SMBSERVER if the first name fails. */ if (nmb_name_equal(&called, &smbservername)) { /* * The name used was *SMBSERVER, don't bother with another name. */ DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER with error %s.\n", desthost, cli_errstr(cli) )); return False; } /* * We need to close the connection here but can't call cli_shutdown as * will free an allocated cli struct. cli_close_connection was invented * for this purpose. JRA. Based on work by "Kim R. Pedersen" <*****@*****.**>. */ cli_close_connection(cli); if (!cli_initialise(cli) || !cli_connect(cli, desthost, pdest_ip) || !cli_session_request(cli, &calling, &smbservername)) { DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) )); return False; } } return True; }
/**************************************************************************** Deal with a successful node status response. ****************************************************************************/ static void node_status_response(struct subnet_record *subrec, struct response_record *rrec, struct packet_struct *p) { struct nmb_packet *nmb = &p->packet.nmb; struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name; struct nmb_name *answer_name = &nmb->answers->rr_name; /* Sanity check. Ensure that the answer name in the incoming packet is the same as the requested name in the outgoing packet. */ if(!nmb_name_equal(question_name, answer_name)) { DEBUG(0,("node_status_response: Answer name %s differs from question \ name %s.\n", namestr(answer_name), namestr(question_name))); return; }
static void register_name_response(struct subnet_record *subrec, struct response_record *rrec, struct packet_struct *p) { /* * If we are registering broadcast, then getting a response is an * error - we do not have the name. If we are registering unicast, * then we expect to get a response. */ struct nmb_packet *nmb = &p->packet.nmb; BOOL bcast = nmb->header.nm_flags.bcast; BOOL success = True; struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name; struct nmb_name *answer_name = &nmb->answers->rr_name; struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb; int ttl = 0; uint16 nb_flags = 0; struct in_addr register_ip; fstring reg_name; putip(®ister_ip,&sent_nmb->additional->rdata[2]); fstrcpy(reg_name, inet_ntoa(register_ip)); if (subrec == unicast_subnet) { /* we know that this wins server is definately alive - for the moment! */ wins_srv_alive(rrec->packet->ip, register_ip); } /* Sanity check. Ensure that the answer name in the incoming packet is the same as the requested name in the outgoing packet. */ if(!question_name || !answer_name) { DEBUG(0,("register_name_response: malformed response (%s is NULL).\n", question_name ? "question_name" : "answer_name" )); return; } if(!nmb_name_equal(question_name, answer_name)) { DEBUG(0,("register_name_response: Answer name %s differs from question name %s.\n", nmb_namestr(answer_name), nmb_namestr(question_name))); return; } if(bcast) { /* * Special hack to cope with old Samba nmbd's. * Earlier versions of Samba (up to 1.9.16p11) respond * to a broadcast name registration of WORKGROUP<1b> when * they should not. Hence, until these versions are gone, * we should treat such errors as success for this particular * case only. [email protected]. */ #if 1 /* OLD_SAMBA_SERVER_HACK */ unstring ans_name; pull_ascii_nstring(ans_name, sizeof(ans_name), answer_name->name); if((nmb->header.rcode == ACT_ERR) && strequal(lp_workgroup(), ans_name) && (answer_name->name_type == 0x1b)) { /* Pretend we did not get this. */ rrec->num_msgs--; DEBUG(5,("register_name_response: Ignoring broadcast response to registration of name %s due to old Samba server bug.\n", nmb_namestr(answer_name))); return; } #endif /* OLD_SAMBA_SERVER_HACK */ /* Someone else has the name. Log the problem. */ DEBUG(1,("register_name_response: Failed to register name %s IP %s on subnet %s via broadcast. Error code was %d. Reject came from IP %s\n", nmb_namestr(answer_name), reg_name, subrec->subnet_name, nmb->header.rcode, inet_ntoa(p->ip))); success = False; } else { /* Unicast - check to see if the response allows us to have the name. */ if (nmb->header.opcode == NMB_WACK_OPCODE) { /* WINS server is telling us to wait. Pretend we didn't get the response but don't send out any more register requests. */ DEBUG(5,("register_name_response: WACK from WINS server %s in registering name %s IP %s\n", inet_ntoa(p->ip), nmb_namestr(answer_name), reg_name)); rrec->repeat_count = 0; /* How long we should wait for. */ rrec->repeat_time = p->timestamp + nmb->answers->ttl; rrec->num_msgs--; return; } else if (nmb->header.rcode != 0) { /* Error code - we didn't get the name. */ success = False; DEBUG(0,("register_name_response: %sserver at IP %s rejected our name registration of %s IP %s with error code %d.\n", subrec==unicast_subnet?"WINS ":"", inet_ntoa(p->ip), nmb_namestr(answer_name), reg_name, nmb->header.rcode)); } else { success = True; /* Get the data we need to pass to the success function. */ nb_flags = get_nb_flags(nmb->answers->rdata); ttl = nmb->answers->ttl; /* send off a registration for the next IP, if any */ wins_next_registration(rrec); } } DEBUG(5,("register_name_response: %s in registering %sname %s IP %s with %s.\n", success ? "success" : "failure", subrec==unicast_subnet?"WINS ":"", nmb_namestr(answer_name), reg_name, inet_ntoa(rrec->packet->ip))); if(success) { /* Enter the registered name into the subnet name database before calling the success function. */ standard_success_register(subrec, rrec->userdata, answer_name, nb_flags, ttl, register_ip); if( rrec->success_fn) (*(register_name_success_function)rrec->success_fn)(subrec, rrec->userdata, answer_name, nb_flags, ttl, register_ip); } else { if( rrec->fail_fn) (*(register_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name); /* Remove the name. */ standard_fail_register( subrec, rrec, question_name); } /* Ensure we don't retry. */ remove_response_record(subrec, rrec); }
/*************************************************************************** check the DNS queue ****************************************************************************/ void run_dns_queue(void) { struct query_record r; struct packet_struct *p, *p2; struct name_record *namerec; int size; if (fd_in == -1) return; /* Allow SIGTERM to kill us. */ BlockSignals(False, SIGTERM); if (!process_exists(child_pid)) { close(fd_in); start_async_dns(); } if ((size=read_data(fd_in, (char *)&r, sizeof(r))) != sizeof(r)) { if (size) { DEBUG(0,("Incomplete DNS answer from child!\n")); fd_in = -1; } BlockSignals(True, SIGTERM); return; } BlockSignals(True, SIGTERM); namerec = add_dns_result(&r.name, r.result); if (dns_current) { if (query_current(&r)) { DEBUG(3,("DNS calling send_wins_name_query_response\n")); in_dns = 1; if(namerec == NULL) send_wins_name_query_response(NAM_ERR, dns_current, NULL); else send_wins_name_query_response(0,dns_current,namerec); in_dns = 0; } dns_current->locked = False; free_packet(dns_current); dns_current = NULL; } /* loop over the whole dns queue looking for entries that match the result we just got */ for (p = dns_queue; p;) { struct nmb_packet *nmb = &p->packet.nmb; struct nmb_name *question = &nmb->question.question_name; if (nmb_name_equal(question, &r.name)) { DEBUG(3,("DNS calling send_wins_name_query_response\n")); in_dns = 1; if(namerec == NULL) send_wins_name_query_response(NAM_ERR, p, NULL); else send_wins_name_query_response(0,p,namerec); in_dns = 0; p->locked = False; if (p->prev) p->prev->next = p->next; else dns_queue = p->next; if (p->next) p->next->prev = p->prev; p2 = p->next; free_packet(p); p = p2; } else { p = p->next; } } if (dns_queue) { dns_current = dns_queue; dns_queue = dns_queue->next; if (dns_queue) dns_queue->prev = NULL; dns_current->next = NULL; if (!write_child(dns_current)) { DEBUG(3,("failed to send DNS query to child!\n")); return; } } }
/*************************************************************************** check if a particular name is already being queried ****************************************************************************/ static BOOL query_current(struct query_record *r) { return dns_current && nmb_name_equal(&r->name, &dns_current->packet.nmb.question.question_name); }
static void release_name_response(struct subnet_record *subrec, struct response_record *rrec, struct packet_struct *p) { /* * If we are releasing broadcast, then getting a response is an * error. If we are releasing unicast, then we expect to get a response. */ struct nmb_packet *nmb = &p->packet.nmb; bool bcast = nmb->header.nm_flags.bcast; bool success = True; struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name; struct nmb_name *answer_name = &nmb->answers->rr_name; struct in_addr released_ip; /* Sanity check. Ensure that the answer name in the incoming packet is the same as the requested name in the outgoing packet. */ if (!nmb_name_equal(question_name, answer_name)) { DEBUG(0,("release_name_response: Answer name %s differs from question name %s.\n", nmb_namestr(answer_name), nmb_namestr(question_name))); return; } if (bcast) { /* Someone sent a response to a bcast release? ignore it. */ return; } /* Unicast - check to see if the response allows us to release the name. */ if (nmb->header.rcode != 0) { /* Error code - we were told not to release the name ! What now ! */ success = False; DEBUG(0,("release_name_response: WINS server at IP %s rejected our \ name release of name %s with error code %d.\n", inet_ntoa(p->ip), nmb_namestr(answer_name), nmb->header.rcode)); } else if (nmb->header.opcode == NMB_WACK_OPCODE) { /* WINS server is telling us to wait. Pretend we didn't get the response but don't send out any more release requests. */ DEBUG(5,("release_name_response: WACK from WINS server %s in releasing \ name %s on subnet %s.\n", inet_ntoa(p->ip), nmb_namestr(answer_name), subrec->subnet_name)); rrec->repeat_count = 0; /* How long we should wait for. */ rrec->repeat_time = p->timestamp + nmb->answers->ttl; rrec->num_msgs--; return; } DEBUG(5,("release_name_response: %s in releasing name %s on subnet %s.\n", success ? "success" : "failure", nmb_namestr(answer_name), subrec->subnet_name)); if (success) { putip((char*)&released_ip ,&nmb->answers->rdata[2]); if(rrec->success_fn) (*(release_name_success_function)rrec->success_fn)(subrec, rrec->userdata, answer_name, released_ip); standard_success_release( subrec, rrec->userdata, answer_name, released_ip); } else { /* We have no standard_fail_release - maybe we should add one ? */ if (rrec->fail_fn) { (*(release_name_fail_function)rrec->fail_fn)(subrec, rrec, answer_name); } } remove_response_record(subrec, rrec); }