summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/proto.h2
-rw-r--r--source3/libsmb/clidgram.c14
-rw-r--r--source3/libsmb/clidgram.h4
-rw-r--r--source3/libsmb/dsgetdcname.c8
-rw-r--r--source3/libsmb/namequery.c35
-rw-r--r--source3/libsmb/unexpected.c133
-rw-r--r--source3/nmbd/nmbd.c4
-rw-r--r--source3/nmbd/nmbd_packets.c7
-rw-r--r--source3/winbindd/winbindd_cm.c7
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);