summaryrefslogtreecommitdiff
path: root/source3/libsmb/namequery.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/libsmb/namequery.c')
-rw-r--r--source3/libsmb/namequery.c239
1 files changed, 174 insertions, 65 deletions
diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c
index 8eb4cea508..96de053e81 100644
--- a/source3/libsmb/namequery.c
+++ b/source3/libsmb/namequery.c
@@ -690,29 +690,54 @@ static bool send_packet_request(struct packet_struct *p)
structures holding the returned names or NULL if the query failed.
**************************************************************************/
-NTSTATUS node_status_query(int fd,
- struct nmb_name *name,
- const struct sockaddr_storage *to_ss,
- TALLOC_CTX *mem_ctx,
- struct node_status **names,
- int *num_names,
- struct node_status_extra *extra)
+struct node_status_query_state {
+ struct sockaddr_storage my_addr;
+ struct sockaddr_storage addr;
+ uint8_t buf[1024];
+ ssize_t buflen;
+ struct packet_struct *packet;
+};
+
+static int node_status_query_state_destructor(
+ struct node_status_query_state *s);
+static bool node_status_query_validator(struct packet_struct *p,
+ void *private_data);
+static void node_status_query_done(struct tevent_req *subreq);
+
+struct tevent_req *node_status_query_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct nmb_name *name,
+ const struct sockaddr_storage *addr)
{
- bool found=False;
- int retries = 2;
- int retry_time = 2000;
- struct timespec tp;
+ struct tevent_req *req, *subreq;
+ struct node_status_query_state *state;
struct packet_struct p;
- struct packet_struct *p2;
struct nmb_packet *nmb = &p.packet.nmb;
- struct node_status *ret;
+ struct sockaddr_in *in_addr;
- ZERO_STRUCT(p);
+ req = tevent_req_create(mem_ctx, &state,
+ struct node_status_query_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ talloc_set_destructor(state, node_status_query_state_destructor);
- if (to_ss->ss_family != AF_INET) {
+ if (addr->ss_family != AF_INET) {
/* Can't do node status to IPv6 */
- return NT_STATUS_INVALID_ADDRESS;
+ tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS);
+ return tevent_req_post(req, ev);
+ }
+
+ state->addr = *addr;
+ in_addr = (struct sockaddr_in *)(void *)&state->addr;
+ in_addr->sin_port = htons(NMB_PORT);
+
+ if (!interpret_string_addr(&state->my_addr, lp_socket_address(),
+ AI_NUMERICHOST|AI_PASSIVE)) {
+ zero_sockaddr(&state->my_addr);
}
+
+ ZERO_STRUCT(p);
nmb->header.name_trn_id = generate_trn_id();
nmb->header.opcode = 0;
nmb->header.response = false;
@@ -730,62 +755,152 @@ NTSTATUS node_status_query(int fd,
nmb->question.question_type = 0x21;
nmb->question.question_class = 0x1;
- p.ip = ((const struct sockaddr_in *)to_ss)->sin_addr;
+#if DEBUG_UNEXPECTED
+ p.ip = in_addr->sin_addr;
p.port = NMB_PORT;
p.recv_fd = -1;
- p.send_fd = fd;
+ p.send_fd = -1;
p.timestamp = time(NULL);
p.packet_type = NMB_PACKET;
- clock_gettime_mono(&tp);
+ {
+ pid_t nmbd_pid = pidfile_pid("nmbd");
- if (!send_packet_request(&p))
- return NT_STATUS_NOT_FOUND;
+ if (nmbd_pid) {
+ struct messaging_context *msg_ctx = messaging_init(
+ state, procid_self(), ev);
+ /* Try nmbd. */
+ messaging_send_buf(msg_ctx,
+ pid_to_procid(nmbd_pid),
+ MSG_SEND_PACKET,
+ (uint8_t *)&p,
+ sizeof(struct packet_struct));
+ TALLOC_FREE(msg_ctx);
+ }
+ }
+#endif
- retries--;
+ state->buflen = build_packet((char *)state->buf, sizeof(state->buf),
+ &p);
+ if (state->buflen == 0) {
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ DEBUG(10, ("build_packet failed\n"));
+ return tevent_req_post(req, ev);
+ }
- while (1) {
- struct timespec tp2;
- clock_gettime_mono(&tp2);
- if (nsec_time_diff(&tp2,&tp)/1000000 > retry_time) {
- if (!retries)
- break;
- if (!found && !send_packet_request(&p))
- return NT_STATUS_NOT_FOUND;
- clock_gettime_mono(&tp);
- retries--;
- }
+ subreq = nb_trans_send(state, ev, &state->my_addr, addr, false,
+ state->buf, state->buflen,
+ NMB_PACKET, nmb->header.name_trn_id,
+ node_status_query_validator, NULL);
+ if (tevent_req_nomem(subreq, req)) {
+ DEBUG(10, ("nb_trans_send failed\n"));
+ return tevent_req_post(req, ev);
+ }
+ if (!tevent_req_set_endtime(req, ev, timeval_current_ofs(10, 0))) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, node_status_query_done, req);
+ return req;
+}
- if ((p2=receive_nmb_packet(fd,90,nmb->header.name_trn_id))) {
- struct nmb_packet *nmb2 = &p2->packet.nmb;
- debug_nmb_packet(p2);
+static bool node_status_query_validator(struct packet_struct *p,
+ void *private_data)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ debug_nmb_packet(p);
+
+ if (nmb->header.opcode != 0 ||
+ nmb->header.nm_flags.bcast ||
+ nmb->header.rcode ||
+ !nmb->header.ancount ||
+ nmb->answers->rr_type != 0x21) {
+ /*
+ * XXXX what do we do with this? could be a redirect,
+ * but we'll discard it for the moment
+ */
+ return false;
+ }
+ return true;
+}
- if (nmb2->header.opcode != 0 ||
- nmb2->header.nm_flags.bcast ||
- nmb2->header.rcode ||
- !nmb2->header.ancount ||
- nmb2->answers->rr_type != 0x21) {
- /* XXXX what do we do with this? could be a
- redirect, but we'll discard it for the
- moment */
- free_packet(p2);
- continue;
- }
+static int node_status_query_state_destructor(
+ struct node_status_query_state *s)
+{
+ if (s->packet != NULL) {
+ free_packet(s->packet);
+ s->packet = NULL;
+ }
+ return 0;
+}
- ret = parse_node_status(
- mem_ctx, &nmb2->answers->rdata[0], num_names,
- extra);
- free_packet(p2);
+static void node_status_query_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct node_status_query_state *state = tevent_req_data(
+ req, struct node_status_query_state);
+ NTSTATUS status;
- if (ret == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
- *names = ret;
- return NT_STATUS_OK;
- }
+ status = nb_trans_recv(subreq, &state->packet);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
}
+ tevent_req_done(req);
+}
+
+NTSTATUS node_status_query_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ struct node_status **pnode_status,
+ int *pnum_names,
+ struct node_status_extra *extra)
+{
+ struct node_status_query_state *state = tevent_req_data(
+ req, struct node_status_query_state);
+ struct node_status *node_status;
+ int num_names;
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ node_status = parse_node_status(
+ mem_ctx, &state->packet->packet.nmb.answers->rdata[0],
+ &num_names, extra);
+ if (node_status == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ *pnode_status = node_status;
+ *pnum_names = num_names;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS node_status_query(TALLOC_CTX *mem_ctx, struct nmb_name *name,
+ const struct sockaddr_storage *addr,
+ struct node_status **pnode_status,
+ int *pnum_names,
+ struct node_status_extra *extra)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
- return NT_STATUS_IO_TIMEOUT;
+ ev = tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = node_status_query_send(ev, ev, name, addr);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = node_status_query_recv(req, mem_ctx, pnode_status,
+ pnum_names, extra);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
}
/****************************************************************************
@@ -804,7 +919,6 @@ bool name_status_find(const char *q_name,
struct node_status *addrs = NULL;
struct nmb_name nname;
int count, i;
- int sock;
bool result = false;
NTSTATUS status;
@@ -835,15 +949,10 @@ bool name_status_find(const char *q_name,
zero_sockaddr(&ss);
}
- sock = open_socket_in(SOCK_DGRAM, 0, 3, &ss, True);
- if (sock == -1)
- goto done;
-
/* W2K PDC's seem not to respond to '*'#0. JRA */
make_nmb_name(&nname, q_name, q_type);
- status = node_status_query(sock, &nname, to_ss, talloc_tos(),
+ status = node_status_query(talloc_tos(), &nname, to_ss,
&addrs, &count, NULL);
- close(sock);
if (!NT_STATUS_IS_OK(status)) {
goto done;
}