diff options
-rw-r--r-- | source3/include/proto.h | 2 | ||||
-rw-r--r-- | source3/libsmb/clidgram.c | 14 | ||||
-rw-r--r-- | source3/libsmb/clidgram.h | 4 | ||||
-rw-r--r-- | source3/libsmb/dsgetdcname.c | 8 | ||||
-rw-r--r-- | source3/libsmb/namequery.c | 35 | ||||
-rw-r--r-- | source3/libsmb/unexpected.c | 133 | ||||
-rw-r--r-- | source3/nmbd/nmbd.c | 4 | ||||
-rw-r--r-- | source3/nmbd/nmbd_packets.c | 7 | ||||
-rw-r--r-- | source3/winbindd/winbindd_cm.c | 7 |
9 files changed, 195 insertions, 19 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h index 10409a40f5..e31d30d96c 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -2907,6 +2907,8 @@ NTSTATUS change_trust_account_password( const char *domain, const char *remote_m /* The following definitions come from libsmb/unexpected.c */ +bool is_requested_send_packet(struct packet_struct *p); +bool store_outstanding_send_packet(struct packet_struct *p); void unexpected_packet(struct packet_struct *p); void clear_unexpected(time_t t); struct packet_struct *receive_unexpected(enum packet_type packet_type, int id, diff --git a/source3/libsmb/clidgram.c b/source3/libsmb/clidgram.c index 919ea93c91..6a7c1b9fd0 100644 --- a/source3/libsmb/clidgram.c +++ b/source3/libsmb/clidgram.c @@ -33,7 +33,8 @@ static bool cli_send_mailslot(struct messaging_context *msg_ctx, char *buf, int len, const char *srcname, int src_type, const char *dstname, int dest_type, - const struct sockaddr_storage *dest_ss) + const struct sockaddr_storage *dest_ss, + int dgm_id) { struct packet_struct p; struct dgram_packet *dgram = &p.packet.dgram; @@ -63,8 +64,7 @@ static bool cli_send_mailslot(struct messaging_context *msg_ctx, dgram->header.flags.node_type = M_NODE; dgram->header.flags.first = True; dgram->header.flags.more = False; - dgram->header.dgm_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) + - ((unsigned)sys_getpid()%(unsigned)100); + dgram->header.dgm_id = dgm_id; /* source ip is filled by nmbd */ dgram->header.dgm_length = 0; /* Let build_dgram() handle this. */ dgram->header.packet_offset = 0; @@ -133,7 +133,8 @@ bool send_getdc_request(TALLOC_CTX *mem_ctx, struct sockaddr_storage *dc_ss, const char *domain_name, const struct dom_sid *sid, - uint32_t nt_version) + uint32_t nt_version, + int dgm_id) { struct in_addr dc_ip; const char *my_acct_name = NULL; @@ -193,12 +194,13 @@ bool send_getdc_request(TALLOC_CTX *mem_ctx, false, NBT_MAILSLOT_NTLOGON, 0, (char *)blob.data, blob.length, global_myname(), 0, domain_name, 0x1c, - dc_ss); + dc_ss, dgm_id); } bool receive_getdc_response(TALLOC_CTX *mem_ctx, struct sockaddr_storage *dc_ss, const char *domain_name, + int dgm_id, uint32_t *nt_version, const char **dc_name, struct netlogon_samlogon_response **samlogon_response) @@ -226,7 +228,7 @@ bool receive_getdc_response(TALLOC_CTX *mem_ctx, return false; } - packet = receive_unexpected(DGRAM_PACKET, 0, my_mailslot); + packet = receive_unexpected(DGRAM_PACKET, dgm_id, my_mailslot); if (packet == NULL) { DEBUG(5, ("Did not receive packet for %s\n", my_mailslot)); diff --git a/source3/libsmb/clidgram.h b/source3/libsmb/clidgram.h index ff98f3b967..b61c0b0f4f 100644 --- a/source3/libsmb/clidgram.h +++ b/source3/libsmb/clidgram.h @@ -7,10 +7,12 @@ bool send_getdc_request(TALLOC_CTX *mem_ctx, struct sockaddr_storage *dc_ss, const char *domain_name, const struct dom_sid *sid, - uint32_t nt_version); + uint32_t nt_version, + int dgm_id); bool receive_getdc_response(TALLOC_CTX *mem_ctx, struct sockaddr_storage *dc_ss, const char *domain_name, + int dgm_id, uint32_t *nt_version, const char **dc_name, struct netlogon_samlogon_response **reply); diff --git a/source3/libsmb/dsgetdcname.c b/source3/libsmb/dsgetdcname.c index 4d0310fd7c..1b57c047e8 100644 --- a/source3/libsmb/dsgetdcname.c +++ b/source3/libsmb/dsgetdcname.c @@ -937,6 +937,11 @@ static NTSTATUS process_dc_netbios(TALLOC_CTX *mem_ctx, DEBUG(10,("process_dc_netbios\n")); for (i=0; i<num_dcs; i++) { + uint16_t val; + int dgm_id; + + generate_random_buffer((uint8_t *)&val, 2); + dgm_id = val; ip_list.ss = dclist[i].ss; ip_list.port = 0; @@ -947,7 +952,7 @@ static NTSTATUS process_dc_netbios(TALLOC_CTX *mem_ctx, if (send_getdc_request(mem_ctx, msg_ctx, &dclist[i].ss, domain_name, - NULL, nt_version)) + NULL, nt_version, dgm_id)) { int k; smb_msleep(300); @@ -955,6 +960,7 @@ static NTSTATUS process_dc_netbios(TALLOC_CTX *mem_ctx, if (receive_getdc_response(mem_ctx, &dclist[i].ss, domain_name, + dgm_id, &nt_version, &dc_name, &r)) { diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c index d1fb5ab817..6ff5f7112a 100644 --- a/source3/libsmb/namequery.c +++ b/source3/libsmb/namequery.c @@ -22,6 +22,7 @@ #include "libads/sitename_cache.h" #include "libads/dns.h" #include "../libcli/netlogon.h" +#include "librpc/gen_ndr/messaging.h" /* nmbd.c sets this to True. */ bool global_in_nmbd = False; @@ -246,6 +247,31 @@ static NODE_STATUS_STRUCT *parse_node_status(char *p, return ret; } +/**************************************************************************** + Try and send a request to nmbd to send a packet_struct packet first. + If this fails, use send_packet(). +**************************************************************************/ + +static bool send_packet_request(struct packet_struct *p) +{ + struct messaging_context *msg_ctx = server_messaging_context(); + if (msg_ctx) { + pid_t nmbd_pid = pidfile_pid("nmbd"); + + if (nmbd_pid) { + /* Try nmbd. */ + if (NT_STATUS_IS_OK(messaging_send_buf(msg_ctx, + pid_to_procid(nmbd_pid), + MSG_SEND_PACKET, + (uint8_t *)p, + sizeof(struct packet_struct)))) { + return true; + } + } + } + + return send_packet(p); +} /**************************************************************************** Do a NBT node status query on an open socket and return an array of @@ -299,7 +325,7 @@ NODE_STATUS_STRUCT *node_status_query(int fd, clock_gettime_mono(&tp); - if (!send_packet(&p)) + if (!send_packet_request(&p)) return NULL; retries--; @@ -310,7 +336,7 @@ NODE_STATUS_STRUCT *node_status_query(int fd, if (nsec_time_diff(&tp2,&tp)/1000000 > retry_time) { if (!retries) break; - if (!found && !send_packet(&p)) + if (!found && !send_packet_request(&p)) return NULL; clock_gettime_mono(&tp); retries--; @@ -707,7 +733,7 @@ struct sockaddr_storage *name_query(int fd, clock_gettime_mono(&tp); - if (!send_packet(&p)) + if (!send_packet_request(&p)) return NULL; retries--; @@ -719,12 +745,11 @@ struct sockaddr_storage *name_query(int fd, if (nsec_time_diff(&tp2,&tp)/1000000 > retry_time) { if (!retries) break; - if (!found && !send_packet(&p)) + if (!found && !send_packet_request(&p)) return NULL; clock_gettime_mono(&tp); retries--; } - if ((p2=receive_nmb_packet(fd,90,nmb->header.name_trn_id))) { struct nmb_packet *nmb2 = &p2->packet.nmb; debug_nmb_packet(p2); diff --git a/source3/libsmb/unexpected.c b/source3/libsmb/unexpected.c index 7f864957a7..0f4227de16 100644 --- a/source3/libsmb/unexpected.c +++ b/source3/libsmb/unexpected.c @@ -29,6 +29,117 @@ struct unexpected_key { int count; }; +struct pending_unexpected { + struct pending_unexpected *prev, *next; + enum packet_type packet_type; + int id; + time_t timeout; +}; + +static struct pending_unexpected *pu_list; + +/**************************************************************************** + This function is called when nmbd has received an unexpected packet. + It checks against the list of outstanding packet transaction id's + to see if it should be stored in the unexpected.tdb. +**************************************************************************/ + +static struct pending_unexpected *find_unexpected_packet(struct packet_struct *p) +{ + struct pending_unexpected *pu; + + if (!p) { + return NULL; + } + + for (pu = pu_list; pu; pu = pu->next) { + if (pu->packet_type == p->packet_type) { + int id = (p->packet_type == DGRAM_PACKET) ? + p->packet.dgram.header.dgm_id : + p->packet.nmb.header.name_trn_id; + if (id == pu->id) { + DEBUG(10,("find_unexpected_packet: found packet " + "with id = %d\n", pu->id )); + return pu; + } + } + } + + return NULL; +} + + +/**************************************************************************** + This function is called when nmbd has been given a packet to send out. + It stores a list of outstanding packet transaction id's and the timeout + when they should be removed. +**************************************************************************/ + +bool store_outstanding_send_packet(struct packet_struct *p) +{ + struct pending_unexpected *pu = NULL; + + if (!p) { + return false; + } + + pu = find_unexpected_packet(p); + if (pu) { + /* This is a resend, and we haven't received a + reply yet ! Ignore it. */ + return false; + } + + pu = SMB_MALLOC_P(struct pending_unexpected); + if (!pu || !p) { + return false; + } + + ZERO_STRUCTP(pu); + pu->packet_type = p->packet_type; + pu->id = (p->packet_type == DGRAM_PACKET) ? + p->packet.dgram.header.dgm_id : + p->packet.nmb.header.name_trn_id; + pu->timeout = time(NULL) + 15; + + DLIST_ADD_END(pu_list, pu, struct pending_unexpected *); + + DEBUG(10,("store_outstanding_unexpected_packet: storing packet " + "with id = %d\n", pu->id )); + + return true; +} + +/**************************************************************************** + Return true if this is a reply to a packet we were requested to send. +**************************************************************************/ + +bool is_requested_send_packet(struct packet_struct *p) +{ + return (find_unexpected_packet(p) != NULL); +} + +/**************************************************************************** + This function is called when nmbd has received an unexpected packet. + It checks against the list of outstanding packet transaction id's + to see if it should be stored in the unexpected.tdb. Don't store if + not found. +**************************************************************************/ + +static bool should_store_unexpected_packet(struct packet_struct *p) +{ + struct pending_unexpected *pu = find_unexpected_packet(p); + + if (!pu) { + return false; + } + + /* Remove the outstanding entry. */ + DLIST_REMOVE(pu_list, pu); + SAFE_FREE(pu); + return true; +} + /**************************************************************************** All unexpected packets are passed in here, to be stored in a unexpected packet database. This allows nmblookup and other tools to receive packets @@ -44,6 +155,13 @@ void unexpected_packet(struct packet_struct *p) int len=0; uint32_t enc_ip; + if (!should_store_unexpected_packet(p)) { + DEBUG(10,("Not storing unexpected packet\n")); + return; + } + + DEBUG(10,("unexpected_packet: storing packet\n")); + if (!tdbd) { tdbd = tdb_wrap_open(NULL, lock_path("unexpected.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_DEFAULT|TDB_INCOMPATIBLE_HASH, @@ -108,6 +226,15 @@ static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *st void clear_unexpected(time_t t) { + struct pending_unexpected *pu, *pu_next; + + for (pu = pu_list; pu; pu = pu_next) { + pu_next = pu->next; + if (pu->timeout < t) { + DLIST_REMOVE(pu_list, pu); + } + } + if (!tdbd) return; if ((lastt != 0) && (t < lastt + NMBD_UNEXPECTED_TIMEOUT)) @@ -168,8 +295,10 @@ static int traverse_match(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, if ((state->match_type == NMB_PACKET && p->packet.nmb.header.name_trn_id == state->match_id) || (state->match_type == DGRAM_PACKET && - match_mailslot_name(p, state->match_name))) { + match_mailslot_name(p, state->match_name) && + p->packet.dgram.header.dgm_id == state->match_id)) { state->matched_packet = p; + tdb_delete(ttdb, kbuf); return -1; } @@ -189,7 +318,7 @@ struct packet_struct *receive_unexpected(enum packet_type packet_type, int id, struct receive_unexpected_state state; tdb2 = tdb_wrap_open(talloc_tos(), lock_path("unexpected.tdb"), 0, 0, - O_RDONLY, 0); + O_RDWR, 0); if (!tdb2) return NULL; state.matched_packet = NULL; diff --git a/source3/nmbd/nmbd.c b/source3/nmbd/nmbd.c index d6943b19e6..30bbeaadee 100644 --- a/source3/nmbd/nmbd.c +++ b/source3/nmbd/nmbd.c @@ -460,7 +460,9 @@ static void msg_nmbd_send_packet(struct messaging_context *msg, p->packet.dgram.header.source_port = 138; } - send_packet(p); + if (store_outstanding_send_packet(p)) { + send_packet(p); + } } /**************************************************************************** ** diff --git a/source3/nmbd/nmbd_packets.c b/source3/nmbd/nmbd_packets.c index c80bac46b5..401eb25267 100644 --- a/source3/nmbd/nmbd_packets.c +++ b/source3/nmbd/nmbd_packets.c @@ -1909,6 +1909,7 @@ bool listen_for_packets(bool run_election) const char *packet_name; int client_fd; int client_port; + bool is_requested_send_reply = false; if (sock_array[i] == -1) { continue; @@ -1937,6 +1938,8 @@ bool listen_for_packets(bool run_election) continue; } + is_requested_send_reply = is_requested_send_packet(packet); + /* * If we got a packet on the broadcast socket and interfaces * only is set then check it came from one of our local nets. @@ -1950,7 +1953,8 @@ bool listen_for_packets(bool run_election) continue; } - if ((is_loopback_ip_v4(packet->ip) || ismyip_v4(packet->ip)) && + if (!is_requested_send_reply && + (is_loopback_ip_v4(packet->ip) || ismyip_v4(packet->ip)) && packet->port == client_port) { if (client_port == DGRAM_PORT) { @@ -1968,7 +1972,6 @@ bool listen_for_packets(bool run_election) } } - if (is_processed_packet(processed_packet_list, packet)) { DEBUG(7,("discarding duplicate packet from %s:%d\n", inet_ntoa(packet->ip),packet->port)); diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c index 9de15b08cf..8f641b56d7 100644 --- a/source3/winbindd/winbindd_cm.c +++ b/source3/winbindd/winbindd_cm.c @@ -1122,6 +1122,8 @@ static bool dcip_to_name(TALLOC_CTX *mem_ctx, { struct ip_service ip_list; uint32_t nt_version = NETLOGON_NT_VERSION_1; + int dgm_id; + uint16_t val; ip_list.ss = *pss; ip_list.port = 0; @@ -1187,15 +1189,18 @@ static bool dcip_to_name(TALLOC_CTX *mem_ctx, #endif /* try GETDC requests next */ + generate_random_buffer((uint8_t *)&val, 2); + dgm_id = val; if (send_getdc_request(mem_ctx, winbind_messaging_context(), pss, domain->name, &domain->sid, - nt_version)) { + nt_version, dgm_id)) { const char *dc_name = NULL; int i; smb_msleep(100); for (i=0; i<5; i++) { if (receive_getdc_response(mem_ctx, pss, domain->name, + dgm_id, &nt_version, &dc_name, NULL)) { fstrcpy(name, dc_name); |