diff options
author | Andrew Tridgell <tridge@samba.org> | 2005-01-21 11:18:56 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 13:09:03 -0500 |
commit | 2383787f199c51cdc202a3cef5822a9fe6b8774c (patch) | |
tree | 52419b4e736f5ae1727561a3c9831e899edb35c5 | |
parent | f1aaef3015864f9323711127a4964a8eceff6a52 (diff) | |
download | samba-2383787f199c51cdc202a3cef5822a9fe6b8774c.tar.gz samba-2383787f199c51cdc202a3cef5822a9fe6b8774c.tar.bz2 samba-2383787f199c51cdc202a3cef5822a9fe6b8774c.zip |
r4891: - added a generic resolve_name() async interface in libcli/resolve/,
which will eventually try all resolution methods setup in smb.conf
- only resolution backend at the moment is bcast, which does a
parallel broadcast to all configured network interfaces, and takes
the first reply that comes in (this nicely demonstrates how to do
parallel requests using the async APIs)
- converted all the existing code to use the new resolve_name() api
- removed all the old nmb code (yay!)
(This used to be commit 239c310f255e43dd2d1c2433f666c9faaacbdce3)
-rw-r--r-- | source4/client/client.c | 9 | ||||
-rw-r--r-- | source4/libcli/cliconnect.c | 8 | ||||
-rw-r--r-- | source4/libcli/composite/connect.c | 47 | ||||
-rw-r--r-- | source4/libcli/config.mk | 18 | ||||
-rw-r--r-- | source4/libcli/namequery.c | 1104 | ||||
-rw-r--r-- | source4/libcli/namequery_dc.c | 27 | ||||
-rw-r--r-- | source4/libcli/nbt/libnbt.h | 6 | ||||
-rw-r--r-- | source4/libcli/nbt/namequery.c | 66 | ||||
-rw-r--r-- | source4/libcli/nbt/nbtname.c | 54 | ||||
-rw-r--r-- | source4/libcli/nbt/nbtsocket.c | 48 | ||||
-rw-r--r-- | source4/libcli/nmblib.c | 1316 | ||||
-rw-r--r-- | source4/libcli/raw/clisocket.c | 16 | ||||
-rw-r--r-- | source4/libcli/raw/clitransport.c | 47 | ||||
-rw-r--r-- | source4/libcli/raw/libcliraw.h | 3 | ||||
-rw-r--r-- | source4/libcli/resolve/bcast.c | 163 | ||||
-rw-r--r-- | source4/libcli/resolve/resolve.c | 51 | ||||
-rw-r--r-- | source4/libcli/unexpected.c | 170 | ||||
-rw-r--r-- | source4/libnet/libnet_rpc.c | 27 | ||||
-rw-r--r-- | source4/torture/rpc/xplogin.c | 11 | ||||
-rw-r--r-- | source4/torture/torture.c | 29 |
20 files changed, 452 insertions, 2768 deletions
diff --git a/source4/client/client.c b/source4/client/client.c index 6c777bca50..a3631fd710 100644 --- a/source4/client/client.c +++ b/source4/client/client.c @@ -3105,11 +3105,14 @@ handle a message operation ****************************************************************************/ static int do_message_op(void) { - struct nmb_name called, calling; + struct nbt_name called, calling; const char *server_name; - make_nmb_name(&calling, lp_netbios_name(), 0x0); - choose_called_name(&called, desthost, name_type); + calling.name = lp_netbios_name(); + calling.type = NBT_NAME_CLIENT; + calling.scope = NULL; + + nbt_choose_called_name(NULL, &called, desthost, name_type); server_name = dest_ip ? dest_ip : desthost; diff --git a/source4/libcli/cliconnect.c b/source4/libcli/cliconnect.c index 0f916d1eb1..aaed36eb05 100644 --- a/source4/libcli/cliconnect.c +++ b/source4/libcli/cliconnect.c @@ -1,7 +1,9 @@ /* Unix SMB/CIFS implementation. + client connect/disconnect routines - Copyright (C) Andrew Tridgell 2003 + + Copyright (C) Andrew Tridgell 2003-2005 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -49,8 +51,8 @@ BOOL smbcli_socket_connect(struct smbcli_state *cli, const char *server) /* wrapper around smbcli_transport_connect() */ BOOL smbcli_transport_establish(struct smbcli_state *cli, - struct nmb_name *calling, - struct nmb_name *called) + struct nbt_name *calling, + struct nbt_name *called) { return smbcli_transport_connect(cli->transport, calling, called); } diff --git a/source4/libcli/composite/connect.c b/source4/libcli/composite/connect.c index 891d16b4e6..7e08aab0d5 100644 --- a/source4/libcli/composite/connect.c +++ b/source4/libcli/composite/connect.c @@ -26,7 +26,8 @@ #include "libcli/composite/composite.h" /* the stages of this call */ -enum connect_stage {CONNECT_SOCKET, +enum connect_stage {CONNECT_RESOLVE, + CONNECT_SOCKET, CONNECT_SESSION_REQUEST, CONNECT_NEGPROT, CONNECT_SESSION_SETUP, @@ -209,7 +210,7 @@ static NTSTATUS connect_socket(struct smbcli_composite *c, { struct connect_state *state = talloc_get_type(c->private, struct connect_state); NTSTATUS status; - struct nmb_name calling, called; + struct nbt_name calling, called; status = smbcli_sock_connect_recv(state->creq); NT_STATUS_NOT_OK_RETURN(status); @@ -225,8 +226,11 @@ static NTSTATUS connect_socket(struct smbcli_composite *c, return connect_send_negprot(c, io); } - make_nmb_name(&calling, io->in.calling_name, 0x0); - choose_called_name(&called, io->in.called_name, 0x20); + calling.name = io->in.calling_name; + calling.type = NBT_NAME_CLIENT; + calling.scope = NULL; + + nbt_choose_called_name(state, &called, io->in.called_name, NBT_NAME_SERVER); state->req = smbcli_transport_connect_send(state->transport, &calling, &called); NT_STATUS_HAVE_NO_MEMORY(state->req); @@ -239,6 +243,29 @@ static NTSTATUS connect_socket(struct smbcli_composite *c, } +/* + called when name resolution is finished +*/ +static NTSTATUS connect_resolve(struct smbcli_composite *c, + struct smb_composite_connect *io) +{ + struct connect_state *state = talloc_get_type(c->private, struct connect_state); + NTSTATUS status; + const char *address; + + status = resolve_name_recv(state->creq, state, &address); + NT_STATUS_NOT_OK_RETURN(status); + + state->creq = smbcli_sock_connect_send(state->sock, address, state->io->in.port); + NT_STATUS_HAVE_NO_MEMORY(state->creq); + + c->stage = CONNECT_SOCKET; + state->creq->async.private = c; + state->creq->async.fn = composite_handler; + + return NT_STATUS_OK; +} + /* handle and dispatch state transitions @@ -248,6 +275,9 @@ static void state_handler(struct smbcli_composite *c) struct connect_state *state = talloc_get_type(c->private, struct connect_state); switch (c->stage) { + case CONNECT_RESOLVE: + c->status = connect_resolve(c, state->io); + break; case CONNECT_SOCKET: c->status = connect_socket(c, state->io); break; @@ -301,6 +331,7 @@ struct smbcli_composite *smb_composite_connect_send(struct smb_composite_connect { struct smbcli_composite *c; struct connect_state *state; + struct nbt_name name; c = talloc_zero(NULL, struct smbcli_composite); if (c == NULL) goto failed; @@ -314,11 +345,15 @@ struct smbcli_composite *smb_composite_connect_send(struct smb_composite_connect state->io = io; c->state = SMBCLI_REQUEST_SEND; - c->stage = CONNECT_SOCKET; + c->stage = CONNECT_RESOLVE; c->event_ctx = state->sock->event.ctx; c->private = state; - state->creq = smbcli_sock_connect_send(state->sock, io->in.dest_host, io->in.port); + name.name = io->in.dest_host; + name.type = NBT_NAME_SERVER; + name.scope = NULL; + + state->creq = resolve_name_send(&name, c->event_ctx); if (state->creq == NULL) goto failed; state->creq->async.private = c; diff --git a/source4/libcli/config.mk b/source4/libcli/config.mk index 87866db66d..21cfed8987 100644 --- a/source4/libcli/config.mk +++ b/source4/libcli/config.mk @@ -8,15 +8,9 @@ ADD_OBJ_FILES = libcli/util/asn1.o \ libcli/util/smbdes.o \ libcli/util/smbencrypt.o -[SUBSYSTEM::LIBCLI_NMB] -ADD_OBJ_FILES = libcli/unexpected.o \ - libcli/namecache.o \ - libcli/nmblib.o \ - libcli/namequery.o -REQUIRED_SUBSYSTEMS = RPC_NDR_LSA - [SUBSYSTEM::LIBCLI_LSA] ADD_OBJ_FILES = libcli/util/clilsa.o +REQUIRED_SUBSYSTEMS = RPC_NDR_LSA [SUBSYSTEM::LIBCLI_COMPOSITE] ADD_OBJ_FILES = \ @@ -33,6 +27,12 @@ ADD_OBJ_FILES = \ libcli/nbt/namequery.o REQUIRED_SUBSYSTEMS = NDR_NBT +[SUBSYSTEM::LIBCLI_RESOLVE] +ADD_OBJ_FILES = \ + libcli/resolve/resolve.o \ + libcli/resolve/bcast.o +REQUIRED_SUBSYSTEMS = LIBCLI_NBT + [SUBSYSTEM::LIBCLI] -REQUIRED_SUBSYSTEMS = LIBCLI_RAW LIBCLI_UTILS LIBCLI_AUTH LIBCLI_NMB \ - LIBCLI_COMPOSITE LIBCLI_NBT +REQUIRED_SUBSYSTEMS = LIBCLI_RAW LIBCLI_UTILS LIBCLI_AUTH \ + LIBCLI_COMPOSITE LIBCLI_NBT LIBCLI_RESOLVE diff --git a/source4/libcli/namequery.c b/source4/libcli/namequery.c deleted file mode 100644 index c440a604c7..0000000000 --- a/source4/libcli/namequery.c +++ /dev/null @@ -1,1104 +0,0 @@ -/* - Unix SMB/CIFS implementation. - name query routines - Copyright (C) Andrew Tridgell 1994-1998 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include "includes.h" -#include "system/network.h" -#include "system/time.h" - -/* A netbios node status array element. */ -struct node_status { - char name[16]; - uint8_t type; - uint8_t flags; -}; - - -/* nmbd.c sets this to True. */ -BOOL global_in_nmbd = False; - -/**************************************************************************** -generate a random trn_id -****************************************************************************/ -static int generate_trn_id(void) -{ - static int trn_id; - - if (trn_id == 0) { - sys_srandom(getpid()); - } - - trn_id = sys_random(); - - return trn_id % (uint_t)0x7FFF; -} - - -/**************************************************************************** - parse a node status response into an array of structures -****************************************************************************/ -static struct node_status *parse_node_status(char *p, int *num_names) -{ - struct node_status *ret; - int i; - - *num_names = CVAL(p,0); - - if (*num_names == 0) return NULL; - - ret = malloc_array_p(struct node_status, *num_names); - if (!ret) return NULL; - - p++; - for (i=0;i< *num_names;i++) { - StrnCpy(ret[i].name,p,15); - trim_string(ret[i].name,NULL," "); - ret[i].type = CVAL(p,15); - ret[i].flags = p[16]; - p += 18; - DEBUG(10, ("%s#%02x: flags = 0x%02x\n", ret[i].name, - ret[i].type, ret[i].flags)); - } - return ret; -} - - -/**************************************************************************** -do a NBT node status query on an open socket and return an array of -structures holding the returned names or NULL if the query failed -**************************************************************************/ -struct node_status *node_status_query(int fd,struct nmb_name *name, - struct ipv4_addr to_ip, int *num_names) -{ - BOOL found=False; - int retries = 2; - int retry_time = 2000; - struct timeval tval; - struct packet_struct p; - struct packet_struct *p2; - struct nmb_packet *nmb = &p.packet.nmb; - struct node_status *ret; - - ZERO_STRUCT(p); - - nmb->header.name_trn_id = generate_trn_id(); - nmb->header.opcode = 0; - nmb->header.response = False; - nmb->header.nm_flags.bcast = False; - nmb->header.nm_flags.recursion_available = False; - nmb->header.nm_flags.recursion_desired = False; - nmb->header.nm_flags.trunc = False; - nmb->header.nm_flags.authoritative = False; - nmb->header.rcode = 0; - nmb->header.qdcount = 1; - nmb->header.ancount = 0; - nmb->header.nscount = 0; - nmb->header.arcount = 0; - nmb->question.question_name = *name; - nmb->question.question_type = 0x21; - nmb->question.question_class = 0x1; - - p.ip = to_ip; - p.port = NMB_PORT; - p.fd = fd; - p.timestamp = time(NULL); - p.packet_type = NMB_PACKET; - - GetTimeOfDay(&tval); - - if (!send_packet(&p)) - return NULL; - - retries--; - - while (1) { - struct timeval tval2; - GetTimeOfDay(&tval2); - if (TvalDiff(&tval,&tval2) > retry_time) { - if (!retries) - break; - if (!found && !send_packet(&p)) - return NULL; - GetTimeOfDay(&tval); - retries--; - } - - if ((p2=receive_nmb_packet(fd,90,nmb->header.name_trn_id))) { - struct nmb_packet *nmb2 = &p2->packet.nmb; - debug_nmb_packet(p2); - - 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; - } - - ret = parse_node_status(&nmb2->answers->rdata[0], num_names); - free_packet(p2); - return ret; - } - } - - return NULL; -} - - -/**************************************************************************** -find the first type XX name in a node status reply - used for finding -a servers name given its IP -return the matched name in *name -**************************************************************************/ - -BOOL name_status_find(const char *q_name, int q_type, int type, struct ipv4_addr to_ip, char *name) -{ - struct node_status *status = NULL; - struct nmb_name nname; - int count, i; - int sock; - BOOL result = False; - - if (lp_disable_netbios()) { - DEBUG(5,("name_status_find(%s#%02x): netbios is disabled\n", q_name, q_type)); - return False; - } - - DEBUG(10, ("name_status_find: looking up %s#%02x at %s\n", q_name, - q_type, sys_inet_ntoa(to_ip))); - - sock = open_socket_in(SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), 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_ip, &count); - close(sock); - if (!status) - goto done; - - for (i=0;i<count;i++) { - if (status[i].type == type) - break; - } - if (i == count) - goto done; - - pull_ascii(name, status[i].name, 16, 15, STR_TERMINATE); - result = True; - - done: - SAFE_FREE(status); - - DEBUG(10, ("name_status_find: name %sfound", result ? "" : "not ")); - - if (result) - DEBUGADD(10, (", ip address is %s", sys_inet_ntoa(to_ip))); - - DEBUG(10, ("\n")); - - return result; -} - - -/* - comparison function used by sort_ip_list -*/ -int ip_compare(struct ipv4_addr *ip1, struct ipv4_addr *ip2) -{ - int max_bits1=0, max_bits2=0; - int num_interfaces = iface_count(); - int i; - - for (i=0;i<num_interfaces;i++) { - struct ipv4_addr ip; - int bits1, bits2; - ip = *iface_n_bcast(i); - bits1 = matching_quad_bits((uint8_t *)&ip1->addr, (uint8_t *)&ip.addr); - bits2 = matching_quad_bits((uint8_t *)&ip2->addr, (uint8_t *)&ip.addr); - max_bits1 = MAX(bits1, max_bits1); - max_bits2 = MAX(bits2, max_bits2); - } - - /* bias towards directly reachable IPs */ - if (iface_local(*ip1)) { - max_bits1 += 32; - } - if (iface_local(*ip2)) { - max_bits2 += 32; - } - - return max_bits2 - max_bits1; -} - -/* - sort an IP list so that names that are close to one of our interfaces - are at the top. This prevents the problem where a WINS server returns an IP that - is not reachable from our subnet as the first match -*/ -static void sort_ip_list(struct ipv4_addr *iplist, int count) -{ - if (count <= 1) { - return; - } - - qsort(iplist, count, sizeof(struct ipv4_addr), QSORT_CAST ip_compare); -} - - -/**************************************************************************** - Do a netbios name query to find someones IP. - Returns an array of IP addresses or NULL if none. - *count will be set to the number of addresses returned. - *timed_out is set if we failed by timing out -****************************************************************************/ -struct ipv4_addr *name_query(int fd,const char *name,int name_type, - BOOL bcast,BOOL recurse, - struct ipv4_addr to_ip, int *count, int *flags, - BOOL *timed_out) -{ - BOOL found=False; - int i, retries = 3; - int retry_time = bcast?250:2000; - struct timeval tval; - struct packet_struct p; - struct packet_struct *p2; - struct nmb_packet *nmb = &p.packet.nmb; - struct ipv4_addr *ip_list = NULL; - - if (lp_disable_netbios()) { - DEBUG(5,("name_query(%s#%02x): netbios is disabled\n", name, name_type)); - return NULL; - } - - if (timed_out) { - *timed_out = False; - } - - memset((char *)&p,'\0',sizeof(p)); - (*count) = 0; - (*flags) = 0; - - nmb->header.name_trn_id = generate_trn_id(); - nmb->header.opcode = 0; - nmb->header.response = False; - nmb->header.nm_flags.bcast = bcast; - nmb->header.nm_flags.recursion_available = False; - nmb->header.nm_flags.recursion_desired = recurse; - nmb->header.nm_flags.trunc = False; - nmb->header.nm_flags.authoritative = False; - nmb->header.rcode = 0; - nmb->header.qdcount = 1; - nmb->header.ancount = 0; - nmb->header.nscount = 0; - nmb->header.arcount = 0; - - make_nmb_name(&nmb->question.question_name,name,name_type); - - nmb->question.question_type = 0x20; - nmb->question.question_class = 0x1; - - p.ip = to_ip; - p.port = NMB_PORT; - p.fd = fd; - p.timestamp = time(NULL); - p.packet_type = NMB_PACKET; - - GetTimeOfDay(&tval); - - if (!send_packet(&p)) - return NULL; - - retries--; - - while (1) { - struct timeval tval2; - struct ipv4_addr *tmp_ip_list; - - GetTimeOfDay(&tval2); - if (TvalDiff(&tval,&tval2) > retry_time) { - if (!retries) - break; - if (!found && !send_packet(&p)) - return NULL; - GetTimeOfDay(&tval); - retries--; - } - - if ((p2=receive_nmb_packet(fd,90,nmb->header.name_trn_id))) { - struct nmb_packet *nmb2 = &p2->packet.nmb; - debug_nmb_packet(p2); - - /* If we get a Negative Name Query Response from a WINS - * server, we should report it and give up. - */ - if( 0 == nmb2->header.opcode /* A query response */ - && !(bcast) /* from a WINS server */ - && nmb2->header.rcode /* Error returned */ - ) { - - if (DEBUGLVL(3)) { - /* Only executed if DEBUGLEVEL >= 3 */ - DEBUG(3,("Negative name query response, rcode 0x%02x: ", nmb2->header.rcode )); - switch( nmb2->header.rcode ) { - case 0x01: - DEBUG(3,("Request was invalidly formatted.\n" )); - break; - case 0x02: - DEBUG(3,("Problem with NBNS, cannot process name.\n")); - break; - case 0x03: - DEBUG(3,("The name requested does not exist.\n" )); - break; - case 0x04: - DEBUG(3,("Unsupported request error.\n" )); - break; - case 0x05: - DEBUG(3,("Query refused error.\n" )); - break; - default: - DEBUG(3,("Unrecognized error code.\n" )); - break; - } - } - free_packet(p2); - return( NULL ); - } - - if (nmb2->header.opcode != 0 || - nmb2->header.nm_flags.bcast || - nmb2->header.rcode || - !nmb2->header.ancount) { - /* - * XXXX what do we do with this? Could be a - * redirect, but we'll discard it for the - * moment. - */ - free_packet(p2); - continue; - } - - tmp_ip_list = realloc_p(ip_list, - struct ipv4_addr, - (*count) + nmb2->answers->rdlength/6); - - if (!tmp_ip_list) { - DEBUG(0,("name_query: realloc_p failed.\n")); - SAFE_FREE(ip_list); - } - - ip_list = tmp_ip_list; - - if (ip_list) { - DEBUG(2,("Got a positive name query response from %s ( ", sys_inet_ntoa(p2->ip))); - for (i=0;i<nmb2->answers->rdlength/6;i++) { - putip((char *)&ip_list[(*count)],&nmb2->answers->rdata[2+i*6]); - DEBUGADD(2,("%s ",sys_inet_ntoa(ip_list[(*count)]))); - (*count)++; - } - DEBUGADD(2,(")\n")); - } - - found=True; - retries=0; - /* We add the flags back ... */ - if (nmb2->header.response) - (*flags) |= NM_FLAGS_RS; - if (nmb2->header.nm_flags.authoritative) - (*flags) |= NM_FLAGS_AA; - if (nmb2->header.nm_flags.trunc) - (*flags) |= NM_FLAGS_TC; - if (nmb2->header.nm_flags.recursion_desired) - (*flags) |= NM_FLAGS_RD; - if (nmb2->header.nm_flags.recursion_available) - (*flags) |= NM_FLAGS_RA; - if (nmb2->header.nm_flags.bcast) - (*flags) |= NM_FLAGS_B; - free_packet(p2); - /* - * If we're doing a unicast lookup we only - * expect one reply. Don't wait the full 2 - * seconds if we got one. JRA. - */ - if(!bcast && found) - break; - } - } - - if (timed_out) { - *timed_out = True; - } - - /* sort the ip list so we choose close servers first if possible */ - sort_ip_list(ip_list, *count); - - return ip_list; -} - -/******************************************************** - Resolve via "bcast" method. -*********************************************************/ - -BOOL name_resolve_bcast(const char *name, int name_type, - struct ipv4_addr **return_ip_list, int *return_count) -{ - int sock, i; - int num_interfaces = iface_count(); - - if (lp_disable_netbios()) { - DEBUG(5,("name_resolve_bcast(%s#%02x): netbios is disabled\n", name, name_type)); - return False; - } - - *return_ip_list = NULL; - *return_count = 0; - - /* - * "bcast" means do a broadcast lookup on all the local interfaces. - */ - - DEBUG(3,("name_resolve_bcast: Attempting broadcast lookup for name %s<0x%x>\n", name, name_type)); - - sock = open_socket_in( SOCK_DGRAM, 0, 3, - interpret_addr(lp_socket_address()), True ); - - if (sock == -1) return False; - - set_socket_options(sock,"SO_BROADCAST"); - /* - * Lookup the name on all the interfaces, return on - * the first successful match. - */ - for( i = num_interfaces-1; i >= 0; i--) { - struct ipv4_addr sendto_ip; - int flags; - /* Done this way to fix compiler error on IRIX 5.x */ - sendto_ip = *iface_n_bcast(i); - *return_ip_list = name_query(sock, name, name_type, True, - True, sendto_ip, return_count, &flags, NULL); - if(*return_ip_list != NULL) { - close(sock); - return True; - } - } - - close(sock); - return False; -} - -/******************************************************** - Resolve via "wins" method. -*********************************************************/ -BOOL resolve_wins(TALLOC_CTX *mem_ctx, const char *name, int name_type, - struct ipv4_addr **return_iplist, int *return_count) -{ - int sock, t, i; - char **wins_tags; - struct ipv4_addr src_ip; - - if (lp_disable_netbios()) { - DEBUG(5,("resolve_wins(%s#%02x): netbios is disabled\n", name, name_type)); - return False; - } - - *return_iplist = NULL; - *return_count = 0; - - DEBUG(3,("resolve_wins: Attempting wins lookup for name %s<0x%x>\n", name, name_type)); - - if (wins_srv_count() < 1) { - DEBUG(3,("resolve_wins: WINS server resolution selected and no WINS servers listed.\n")); - return False; - } - - /* we try a lookup on each of the WINS tags in turn */ - wins_tags = wins_srv_tags(); - - if (!wins_tags) { - /* huh? no tags?? give up in disgust */ - return False; - } - - /* the address we will be sending from */ - src_ip = interpret_addr2(lp_socket_address()); - - /* in the worst case we will try every wins server with every - tag! */ - for (t=0; wins_tags && wins_tags[t]; t++) { - int srv_count = wins_srv_count_tag(wins_tags[t]); - for (i=0; i<srv_count; i++) { - struct ipv4_addr wins_ip; - int flags; - BOOL timed_out; - - wins_ip = wins_srv_ip_tag(wins_tags[t], src_ip); - - if (global_in_nmbd && ismyip(wins_ip)) { - /* yikes! we'll loop forever */ - continue; - } - - /* skip any that have been unresponsive lately */ - if (wins_srv_is_dead(wins_ip, src_ip)) { - continue; - } - - DEBUG(3,("resolve_wins: using WINS server %s and tag '%s'\n", sys_inet_ntoa(wins_ip), wins_tags[t])); - - sock = open_socket_in(SOCK_DGRAM, 0, 3, src_ip.addr, True); - if (sock == -1) { - continue; - } - - *return_iplist = name_query(sock,name,name_type, False, - True, wins_ip, return_count, &flags, - &timed_out); - if (*return_iplist != NULL) { - goto success; - } - close(sock); - - if (timed_out) { - /* Timed out wating for WINS server to respond. Mark it dead. */ - wins_srv_died(wins_ip, src_ip); - } else { - /* The name definately isn't in this - group of WINS servers. goto the next group */ - break; - } - } - } - - wins_srv_tags_free(wins_tags); - return False; - -success: - wins_srv_tags_free(wins_tags); - close(sock); - return True; -} - -/******************************************************** - Resolve via "hosts" method. -*********************************************************/ - -static BOOL resolve_hosts(const char *name, - struct ipv4_addr **return_iplist, int *return_count) -{ - /* - * "host" means do a localhost, or dns lookup. - */ - struct hostent *hp; - - *return_iplist = NULL; - *return_count = 0; - - DEBUG(3,("resolve_hosts: Attempting host lookup for name %s<0x20>\n", name)); - - if (((hp = sys_gethostbyname(name)) != NULL) && (hp->h_addr != NULL)) { - struct ipv4_addr return_ip; - putip((char *)&return_ip,(char *)hp->h_addr); - *return_iplist = malloc_p(struct ipv4_addr); - if(*return_iplist == NULL) { - DEBUG(3,("resolve_hosts: malloc fail !\n")); - return False; - } - **return_iplist = return_ip; - *return_count = 1; - return True; - } - return False; -} - -/******************************************************** - Internal interface to resolve a name into an IP address. - Use this function if the string is either an IP address, DNS - or host name or NetBIOS name. This uses the name switch in the - smb.conf to determine the order of name resolution. -*********************************************************/ - -static BOOL internal_resolve_name(TALLOC_CTX *mem_ctx, const char *name, int name_type, - struct ipv4_addr **return_iplist, int *return_count) -{ - char *name_resolve_list; - fstring tok; - const char *ptr; - BOOL allones = (strcmp(name,"255.255.255.255") == 0); - BOOL allzeros = (strcmp(name,"0.0.0.0") == 0); - BOOL is_address = is_ipaddress(name); - BOOL result = False; - struct ipv4_addr *nodupes_iplist; - int i; - - *return_iplist = NULL; - *return_count = 0; - - DEBUG(10, ("internal_resolve_name: looking up %s#%x\n", name, name_type)); - - if (allzeros || allones || is_address) { - *return_iplist = malloc_p(struct ipv4_addr); - if(*return_iplist == NULL) { - DEBUG(3,("internal_resolve_name: malloc fail !\n")); - return False; - } - if(is_address) { - /* if it's in the form of an IP address then get the lib to interpret it */ - if (((*return_iplist)->addr = inet_addr(name)) == 0xFFFFFFFF ){ - DEBUG(1,("internal_resolve_name: inet_addr failed on %s\n", name)); - return False; - } - } else { - (*return_iplist)->addr = allones ? 0xFFFFFFFF : 0; - *return_count = 1; - } - return True; - } - - /* Check netbios name cache */ - - if (namecache_fetch(mem_ctx, name, name_type, return_iplist, return_count)) { - - /* This could be a negative response */ - - return (*return_count > 0); - } - - name_resolve_list = talloc_strdup(mem_ctx, lp_name_resolve_order()); - ptr = name_resolve_list; - if (!ptr || !*ptr) - ptr = "host"; - - while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) { - if((strequal(tok, "host") || strequal(tok, "hosts"))) { - if (name_type == 0x20) { - if (resolve_hosts(name, return_iplist, return_count)) { - result = True; - goto done; - } - } - } else if(strequal( tok, "lmhosts")) { - /* REWRITE: add back in? */ - DEBUG(2,("resolve_name: REWRITE: add lmhosts back?? %s\n", tok)); - } else if(strequal( tok, "wins")) { - /* don't resolve 1D via WINS */ - if (name_type != 0x1D && - resolve_wins(mem_ctx, name, name_type, return_iplist, return_count)) { - result = True; - goto done; - } - } else if(strequal( tok, "bcast")) { - if (name_resolve_bcast(name, name_type, return_iplist, return_count)) { - result = True; - goto done; - } - } else { - DEBUG(0,("resolve_name: unknown name switch type %s\n", tok)); - } - } - - /* All of the resolve_* functions above have returned false. */ - - SAFE_FREE(*return_iplist); - *return_count = 0; - - return False; - - done: - - /* Remove duplicate entries. Some queries, notably #1c (domain - controllers) return the PDC in iplist[0] and then all domain - controllers including the PDC in iplist[1..n]. Iterating over - the iplist when the PDC is down will cause two sets of timeouts. */ - - if (*return_count && (nodupes_iplist = malloc_array_p(struct ipv4_addr, *return_count))) { - int nodupes_count = 0; - - /* Iterate over return_iplist looking for duplicates */ - - for (i = 0; i < *return_count; i++) { - BOOL is_dupe = False; - int j; - - for (j = i + 1; j < *return_count; j++) { - if (ipv4_equal((*return_iplist)[i], - (*return_iplist)[j])) { - is_dupe = True; - break; - } - } - - if (!is_dupe) { - - /* This one not a duplicate */ - - nodupes_iplist[nodupes_count] = (*return_iplist)[i]; - nodupes_count++; - } - } - - /* Switcheroo with original list */ - - free(*return_iplist); - - *return_iplist = nodupes_iplist; - *return_count = nodupes_count; - } - - /* Save in name cache */ - for (i = 0; i < *return_count && DEBUGLEVEL == 100; i++) - DEBUG(100, ("Storing name %s of type %d (ip: %s)\n", name, - name_type, sys_inet_ntoa((*return_iplist)[i]))); - - namecache_store(mem_ctx, name, name_type, *return_count, *return_iplist); - - /* Display some debugging info */ - - DEBUG(10, ("internal_resolve_name: returning %d addresses: ", - *return_count)); - - for (i = 0; i < *return_count; i++) - DEBUGADD(10, ("%s ", sys_inet_ntoa((*return_iplist)[i]))); - - DEBUG(10, ("\n")); - - return result; -} - -/******************************************************** - Internal interface to resolve a name into one IP address. - Use this function if the string is either an IP address, DNS - or host name or NetBIOS name. This uses the name switch in the - smb.conf to determine the order of name resolution. -*********************************************************/ -BOOL resolve_name(TALLOC_CTX *mem_ctx, const char *name, struct ipv4_addr *return_ip, int name_type) -{ - struct ipv4_addr *ip_list = NULL; - int count = 0; - - if (is_ipaddress(name)) { - *return_ip = interpret_addr2(name); - return True; - } - - if (internal_resolve_name(mem_ctx, name, name_type, &ip_list, &count)) { - int i; - /* only return valid addresses for TCP connections */ - for (i=0; i<count; i++) { - const char *ip_str = sys_inet_ntoa(ip_list[i]); - if (ip_str && - strcmp(ip_str, "255.255.255.255") != 0 && - strcmp(ip_str, "0.0.0.0") != 0) { - *return_ip = ip_list[i]; - SAFE_FREE(ip_list); - return True; - } - } - } - SAFE_FREE(ip_list); - return False; -} - -/******************************************************** - Find the IP address of the master browser or DMB for a workgroup. -*********************************************************/ - -BOOL find_master_ip(TALLOC_CTX *mem_ctx, const char *group, struct ipv4_addr *master_ip) -{ - struct ipv4_addr *ip_list = NULL; - int count = 0; - - if (lp_disable_netbios()) { - DEBUG(5,("find_master_ip(%s): netbios is disabled\n", group)); - return False; - } - - if (internal_resolve_name(mem_ctx, group, 0x1D, &ip_list, &count)) { - *master_ip = ip_list[0]; - SAFE_FREE(ip_list); - return True; - } - if(internal_resolve_name(mem_ctx, group, 0x1B, &ip_list, &count)) { - *master_ip = ip_list[0]; - SAFE_FREE(ip_list); - return True; - } - - SAFE_FREE(ip_list); - return False; -} - -/******************************************************** - Lookup a DC name given a Domain name and IP address. -*********************************************************/ - -BOOL lookup_dc_name(const char *srcname, const char *domain, - struct ipv4_addr *dc_ip, char *ret_name) -{ -#if !defined(I_HATE_WINDOWS_REPLY_CODE) - fstring dc_name; - BOOL ret; - - if (lp_disable_netbios()) { - DEBUG(5,("lookup_dc_name(%s): netbios is disabled\n", domain)); - return False; - } - - /* - * Due to the fact win WinNT *sucks* we must do a node status - * query here... JRA. - */ - - *dc_name = '\0'; - - ret = name_status_find(domain, 0x1c, 0x20, *dc_ip, dc_name); - - if(ret && *dc_name) { - fstrcpy(ret_name, dc_name); - return True; - } - - return False; - -#else /* defined(I_HATE_WINDOWS_REPLY_CODE) */ - -JRA - This code is broken with BDC rollover - we need to do a full -NT GETDC call, UNICODE, NT domain SID and uncle tom cobbley and all... - - int retries = 3; - int retry_time = 2000; - struct timeval tval; - struct packet_struct p; - struct dgram_packet *dgram = &p.packet.dgram; - char *ptr,*p2; - char tmp[4]; - int len; - struct sockaddr_in sock_name; - int sock_len = sizeof(sock_name); - const char *mailslot = NET_LOGON_MAILSLOT; - char *mailslot_name; - char buffer[1024]; - char *bufp; - int dgm_id = generate_trn_id(); - int sock = open_socket_in(SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), True ); - - if(sock == -1) - return False; - - /* Find out the transient UDP port we have been allocated. */ - if(getsockname(sock, (struct sockaddr *)&sock_name, &sock_len)<0) { - DEBUG(0,("lookup_pdc_name: Failed to get local UDP port. Error was %s\n", - strerror(errno))); - close(sock); - return False; - } - - /* - * Create the request data. - */ - - memset(buffer,'\0',sizeof(buffer)); - bufp = buffer; - SSVAL(bufp,0,QUERYFORPDC); - bufp += 2; - fstrcpy(bufp,srcname); - bufp += (strlen(bufp) + 1); - slprintf(bufp, sizeof(fstring)-1, "\\MAILSLOT\\NET\\GETDC%d", dgm_id); - mailslot_name = bufp; - bufp += (strlen(bufp) + 1); - bufp = ALIGN2(bufp, buffer); - bufp += push_ucs2(NULL, bufp, srcname, sizeof(buffer) - (bufp - buffer), STR_TERMINATE); - - SIVAL(bufp,0,1); - SSVAL(bufp,4,0xFFFF); - SSVAL(bufp,6,0xFFFF); - bufp += 8; - len = PTR_DIFF(bufp,buffer); - - memset((char *)&p,'\0',sizeof(p)); - - /* DIRECT GROUP or UNIQUE datagram. */ - dgram->header.msg_type = 0x10; - dgram->header.flags.node_type = M_NODE; - dgram->header.flags.first = True; - dgram->header.flags.more = False; - dgram->header.dgm_id = dgm_id; - dgram->header.source_ip = *iface_ip(*pdc_ip); - dgram->header.source_port = ntohs(sock_name.sin_port); - dgram->header.dgm_length = 0; /* Let build_dgram() handle this. */ - dgram->header.packet_offset = 0; - - make_nmb_name(&dgram->source_name,srcname,0); - make_nmb_name(&dgram->dest_name,domain,0x1C); - - ptr = &dgram->data[0]; - - /* Setup the smb part. */ - ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */ - memcpy(tmp,ptr,4); - set_message(ptr,17,17 + len,True); - memcpy(ptr,tmp,4); - - CVAL(ptr,smb_com) = SMBtrans; - SSVAL(ptr,smb_vwv1,len); - SSVAL(ptr,smb_vwv11,len); - SSVAL(ptr,smb_vwv12,70 + strlen(mailslot)); - SSVAL(ptr,smb_vwv13,3); - SSVAL(ptr,smb_vwv14,1); - SSVAL(ptr,smb_vwv15,1); - SSVAL(ptr,smb_vwv16,2); - p2 = smb_buf(ptr); - pstrcpy(p2,mailslot); - p2 = skip_string(p2,1); - - memcpy(p2,buffer,len); - p2 += len; - - dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length. */ - - p.ip = *pdc_ip; - p.port = DGRAM_PORT; - p.fd = sock; - p.timestamp = time(NULL); - p.packet_type = DGRAM_PACKET; - - GetTimeOfDay(&tval); - - if (!send_packet(&p)) { - DEBUG(0,("lookup_pdc_name: send_packet failed.\n")); - close(sock); - return False; - } - - retries--; - - while (1) { - struct timeval tval2; - struct packet_struct *p_ret; - - GetTimeOfDay(&tval2); - if (TvalDiff(&tval,&tval2) > retry_time) { - if (!retries) - break; - if (!send_packet(&p)) { - DEBUG(0,("lookup_pdc_name: send_packet failed.\n")); - close(sock); - return False; - } - GetTimeOfDay(&tval); - retries--; - } - - if ((p_ret = receive_dgram_packet(sock,90,mailslot_name))) { - struct dgram_packet *dgram2 = &p_ret->packet.dgram; - char *buf; - char *buf2; - - buf = &dgram2->data[0]; - buf -= 4; - - if (CVAL(buf,smb_com) != SMBtrans) { - DEBUG(0,("lookup_pdc_name: datagram type %u != SMBtrans(%u)\n", (uint_t) - CVAL(buf,smb_com), (uint_t)SMBtrans )); - free_packet(p_ret); - continue; - } - - len = SVAL(buf,smb_vwv11); - buf2 = smb_base(buf) + SVAL(buf,smb_vwv12); - - if (len <= 0) { - DEBUG(0,("lookup_pdc_name: datagram len < 0 (%d)\n", len )); - free_packet(p_ret); - continue; - } - - DEBUG(4,("lookup_pdc_name: datagram reply from %s to %s IP %s for %s of type %d len=%d\n", - nmb_namestr(&dgram2->source_name),nmb_namestr(&dgram2->dest_name), - sys_inet_ntoa(p_ret->ip), smb_buf(buf),SVAL(buf2,0),len)); - - if(SVAL(buf2,0) != QUERYFORPDC_R) { - DEBUG(0,("lookup_pdc_name: datagram type (%u) != QUERYFORPDC_R(%u)\n", - (uint_t)SVAL(buf,0), (uint_t)QUERYFORPDC_R )); - free_packet(p_ret); - continue; - } - - buf2 += 2; - /* Note this is safe as it is a bounded strcpy. */ - fstrcpy(ret_name, buf2); - ret_name[sizeof(fstring)-1] = '\0'; - close(sock); - free_packet(p_ret); - return True; - } - } - - close(sock); - return False; -#endif /* defined(I_HATE_WINDOWS_REPLY_CODE) */ -} - -/******************************************************** - Get the IP address list of the primary domain controller - for a domain. -*********************************************************/ - -BOOL get_pdc_ip(TALLOC_CTX *mem_ctx, const char *domain, struct ipv4_addr *ip) -{ - struct ipv4_addr *ip_list; - int count; - int i = 0; - - /* Look up #1B name */ - - if (!internal_resolve_name(mem_ctx, domain, 0x1b, &ip_list, &count)) - return False; - - /* if we get more than 1 IP back we have to assume it is a - multi-homed PDC and not a mess up */ - - if ( count > 1 ) { - DEBUG(6,("get_pdc_ip: PDC has %d IP addresses!\n", count)); - - /* look for a local net */ - for ( i=0; i<count; i++ ) { - if ( is_local_net( ip_list[i] ) ) - break; - } - - /* if we hit then end then just grab the first - one from the list */ - - if ( i == count ) - i = 0; - } - - *ip = ip_list[i]; - - SAFE_FREE(ip_list); - - return True; -} - diff --git a/source4/libcli/namequery_dc.c b/source4/libcli/namequery_dc.c deleted file mode 100644 index 49aa42a744..0000000000 --- a/source4/libcli/namequery_dc.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - Winbind daemon connection manager - - Copyright (C) Tim Potter 2001 - Copyright (C) Andrew Bartlett 2002 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - - -#include "includes.h" - - diff --git a/source4/libcli/nbt/libnbt.h b/source4/libcli/nbt/libnbt.h index 3658f1dd77..a7788f791b 100644 --- a/source4/libcli/nbt/libnbt.h +++ b/source4/libcli/nbt/libnbt.h @@ -62,6 +62,12 @@ struct nbt_name_request { const char *reply_addr; int reply_port; } *replies; + + /* information on what to do on completion */ + struct { + void (*fn)(struct nbt_name_request *); + void *private; + } async; }; diff --git a/source4/libcli/nbt/namequery.c b/source4/libcli/nbt/namequery.c index 23a63ede11..05d5e55491 100644 --- a/source4/libcli/nbt/namequery.c +++ b/source4/libcli/nbt/namequery.c @@ -209,69 +209,3 @@ NTSTATUS nbt_name_status(struct nbt_name_socket *nbtsock, } -/* - some test functions - will be removed when nbt is hooked in everywhere -*/ -void test_name_status(const char *name, const char *addr) -{ - struct nbt_name_status io; - NTSTATUS status; - TALLOC_CTX *tmp_ctx = talloc_new(NULL); - struct nbt_name_socket *nbtsock; - int i; - - nbtsock = nbt_name_socket_init(tmp_ctx, NULL); - - io.in.name.name = name; - io.in.name.scope = NULL; - io.in.name.type = NBT_NAME_CLIENT; - io.in.dest_addr = addr; - io.in.timeout = 5; - - status = nbt_name_status(nbtsock, tmp_ctx, &io); - if (!NT_STATUS_IS_OK(status)) { - printf("status failed for %s - %s\n", name, nt_errstr(status)); - talloc_free(tmp_ctx); - exit(1); - return; - } - - printf("Received %d names for %s\n", io.out.status.num_names, io.out.name.name); - for (i=0;i<io.out.status.num_names;i++) { - printf("\t%s#%02x 0x%04x\n", - io.out.status.names[i].name, - io.out.status.names[i].type, - io.out.status.names[i].nb_flags); - } - talloc_free(tmp_ctx); -} - - -void test_name_query(const char *name) -{ - struct nbt_name_query io; - NTSTATUS status; - TALLOC_CTX *tmp_ctx = talloc_new(NULL); - struct nbt_name_socket *nbtsock; - - nbtsock = nbt_name_socket_init(tmp_ctx, NULL); - - io.in.name.name = name; - io.in.name.scope = NULL; - io.in.name.type = NBT_NAME_SERVER; - io.in.dest_addr = "255.255.255.255"; - io.in.broadcast = True; - io.in.wins_lookup = False; - io.in.timeout = 5; - - status = nbt_name_query(nbtsock, tmp_ctx, &io); - if (!NT_STATUS_IS_OK(status)) { - printf("query failed for %s - %s\n", name, nt_errstr(status)); - } else { - printf("response %s is at %s\n", io.out.name.name, io.out.reply_addr); - test_name_status("*", io.out.reply_addr); - } - - talloc_free(tmp_ctx); -} - diff --git a/source4/libcli/nbt/nbtname.c b/source4/libcli/nbt/nbtname.c index c2da1a0ab4..8c46379f0b 100644 --- a/source4/libcli/nbt/nbtname.c +++ b/source4/libcli/nbt/nbtname.c @@ -283,3 +283,57 @@ NTSTATUS ndr_push_nbt_name(struct ndr_push *ndr, int ndr_flags, struct nbt_name return NT_STATUS_OK; } + + +/* + copy a nbt name structure +*/ +NTSTATUS nbt_name_dup(TALLOC_CTX *mem_ctx, struct nbt_name *name, struct nbt_name *newname) +{ + *newname = *name; + newname->name = talloc_strdup(mem_ctx, newname->name); + NT_STATUS_HAVE_NO_MEMORY(newname->name); + newname->scope = talloc_strdup(mem_ctx, newname->scope); + if (name->scope) { + NT_STATUS_HAVE_NO_MEMORY(newname->scope); + } + return NT_STATUS_OK; +} + +/* + push a nbt name into a blob +*/ +NTSTATUS nbt_name_to_blob(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct nbt_name *name) +{ + return ndr_push_struct_blob(blob, mem_ctx, name, + (ndr_push_flags_fn_t)ndr_push_nbt_name); +} + +/* + choose a name to use when calling a server in a NBT session request. + we use heuristics to see if the name we have been given is a IP + address, or a too-long name. If it is then use *SMBSERVER, or a + truncated name +*/ +void nbt_choose_called_name(TALLOC_CTX *mem_ctx, + struct nbt_name *n, const char *name, int type) +{ + n->scope = NULL; + n->type = type; + + if (is_ipaddress(name)) { + n->name = "*SMBSERVER"; + return; + } + if (strlen(name) > 15) { + const char *p = strchr(name, '.'); + if (p - name > 15) { + n->name = "*SMBSERVER"; + return; + } + n->name = talloc_strndup(mem_ctx, name, PTR_DIFF(p, name)); + return; + } + + n->name = talloc_strdup(mem_ctx, name); +} diff --git a/source4/libcli/nbt/nbtsocket.c b/source4/libcli/nbt/nbtsocket.c index 896ed68e98..6d5b450a31 100644 --- a/source4/libcli/nbt/nbtsocket.c +++ b/source4/libcli/nbt/nbtsocket.c @@ -29,6 +29,16 @@ #define NBT_MAX_REPLIES 1000 /* + destroy a nbt socket +*/ +static int nbtsock_destructor(void *ptr) +{ + struct nbt_name_socket *nbtsock = talloc_get_type(ptr, struct nbt_name_socket); + event_remove_fd(nbtsock->event_ctx, nbtsock->fde); + return 0; +} + +/* destroy a pending request */ static int nbt_name_request_destructor(void *ptr) @@ -111,6 +121,9 @@ failed: nbt_name_request_destructor(req); req->status = status; req->state = NBT_REQUEST_ERROR; + if (req->async.fn) { + req->async.fn(req); + } talloc_free(tmp_ctx); return; } @@ -184,6 +197,9 @@ static void nbt_name_socket_recv(struct nbt_name_socket *nbtsock) req->state = NBT_REQUEST_DONE; req->status = NT_STATUS_NO_MEMORY; talloc_free(tmp_ctx); + if (req->async.fn) { + req->async.fn(req); + } return; } @@ -192,15 +208,18 @@ static void nbt_name_socket_recv(struct nbt_name_socket *nbtsock) req->replies[req->num_replies].packet = talloc_steal(req, packet); req->num_replies++; + talloc_free(tmp_ctx); + /* if we don't want multiple replies then we are done */ if (!req->allow_multiple_replies || req->num_replies == NBT_MAX_REPLIES) { nbt_name_request_destructor(req); req->state = NBT_REQUEST_DONE; req->status = NT_STATUS_OK; + if (req->async.fn) { + req->async.fn(req); + } } - - talloc_free(tmp_ctx); } /* @@ -257,6 +276,8 @@ struct nbt_name_socket *nbt_name_socket_init(TALLOC_CTX *mem_ctx, fde.private = nbtsock; nbtsock->fde = event_add_fd(nbtsock->event_ctx, &fde); + talloc_set_destructor(nbtsock, nbtsock_destructor); + return nbtsock; failed: @@ -273,8 +294,16 @@ static void nbt_name_socket_timeout(struct event_context *ev, struct timed_event struct nbt_name_request *req = talloc_get_type(te->private, struct nbt_name_request); nbt_name_request_destructor(req); - req->state = NBT_REQUEST_TIMEOUT; - req->status = NT_STATUS_IO_TIMEOUT; + if (req->num_replies == 0) { + req->state = NBT_REQUEST_TIMEOUT; + req->status = NT_STATUS_IO_TIMEOUT; + } else { + req->state = NBT_REQUEST_DONE; + req->status = NT_STATUS_OK; + } + if (req->async.fn) { + req->async.fn(req); + } } /* @@ -300,14 +329,20 @@ struct nbt_name_request *nbt_name_request_send(struct nbt_name_socket *nbtsock, req->allow_multiple_replies = allow_multiple_replies; req->state = NBT_REQUEST_SEND; + /* we select a random transaction id unless the user supplied one */ if (req->request->name_trn_id == 0) { req->request->name_trn_id = random() % UINT16_MAX; } + /* choose the next available transaction id >= the one asked for. + The strange 2nd call is to try to make the ids less guessable + and less likely to collide. It's not possible to make NBT secure + to ID guessing, but this at least makes accidential collisions + less likely */ id = idr_get_new_above(req->nbtsock->idr, req, req->request->name_trn_id, UINT16_MAX); if (id == -1) { - id = idr_get_new_above(req->nbtsock->idr, req, 1+(random()%10000), + id = idr_get_new_above(req->nbtsock->idr, req, 1+(random()%(UINT16_MAX/2)), UINT16_MAX); } if (id == -1) goto failed; @@ -341,6 +376,9 @@ NTSTATUS nbt_name_request_recv(struct nbt_name_request *req) if (event_loop_once(req->nbtsock->event_ctx) != 0) { req->state = NBT_REQUEST_ERROR; req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR; + if (req->async.fn) { + req->async.fn(req); + } } } return req->status; diff --git a/source4/libcli/nmblib.c b/source4/libcli/nmblib.c deleted file mode 100644 index 0a3f72ba74..0000000000 --- a/source4/libcli/nmblib.c +++ /dev/null @@ -1,1316 +0,0 @@ -/* - Unix SMB/CIFS implementation. - NBT netbios library routines - Copyright (C) Andrew Tridgell 1994-1998 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include "includes.h" -#include "system/network.h" -#include "system/time.h" -#include "system/iconv.h" - -static const struct opcode_names { - const char *nmb_opcode_name; - int opcode; -} nmb_header_opcode_names[] = { - {"Query", 0 }, - {"Registration", 5 }, - {"Release", 6 }, - {"WACK", 7 }, - {"Refresh", 8 }, - {"Refresh(altcode)", 9 }, - {"Multi-homed Registration", 15 }, - {0, -1 } -}; - -/**************************************************************************** - * Lookup a nmb opcode name. - ****************************************************************************/ -static const char *lookup_opcode_name( int opcode ) -{ - const struct opcode_names *op_namep; - int i; - - for(i = 0; nmb_header_opcode_names[i].nmb_opcode_name != 0; i++) { - op_namep = &nmb_header_opcode_names[i]; - if(opcode == op_namep->opcode) - return op_namep->nmb_opcode_name; - } - return "<unknown opcode>"; -} - -/**************************************************************************** - print out a res_rec structure - ****************************************************************************/ -static void debug_nmb_res_rec(struct res_rec *res, const char *hdr) -{ - int i, j; - - DEBUGADD( 4, ( " %s: nmb_name=%s rr_type=%d rr_class=%d ttl=%d\n", - hdr, - nmb_namestr(&res->rr_name), - res->rr_type, - res->rr_class, - res->ttl ) ); - - if( res->rdlength == 0 || res->rdata == NULL ) - return; - - for (i = 0; i < res->rdlength; i+= 16) - { - DEBUGADD(4, (" %s %3x char ", hdr, i)); - - for (j = 0; j < 16; j++) - { - uint8_t x = res->rdata[i+j]; - if (x < 32 || x > 127) x = '.'; - - if (i+j >= res->rdlength) break; - DEBUGADD(4, ("%c", x)); - } - - DEBUGADD(4, (" hex ")); - - for (j = 0; j < 16; j++) - { - if (i+j >= res->rdlength) break; - DEBUGADD(4, ("%02X", (uint8_t)res->rdata[i+j])); - } - - DEBUGADD(4, ("\n")); - } -} - -/**************************************************************************** - process a nmb packet - ****************************************************************************/ -void debug_nmb_packet(struct packet_struct *p) -{ - struct nmb_packet *nmb = &p->packet.nmb; - - if (DEBUGLVL(4)) { - DEBUG(4, ("nmb packet from %s(%d) header: id=%d opcode=%s(%d) response=%s\n", - sys_inet_ntoa(p->ip), p->port, - nmb->header.name_trn_id, - lookup_opcode_name(nmb->header.opcode), - nmb->header.opcode, - BOOLSTR(nmb->header.response))); - DEBUG(4, (" header: flags: bcast=%s rec_avail=%s rec_des=%s trunc=%s auth=%s\n", - BOOLSTR(nmb->header.nm_flags.bcast), - BOOLSTR(nmb->header.nm_flags.recursion_available), - BOOLSTR(nmb->header.nm_flags.recursion_desired), - BOOLSTR(nmb->header.nm_flags.trunc), - BOOLSTR(nmb->header.nm_flags.authoritative))); - DEBUG(4, (" header: rcode=%d qdcount=%d ancount=%d nscount=%d arcount=%d\n", - nmb->header.rcode, - nmb->header.qdcount, - nmb->header.ancount, - nmb->header.nscount, - nmb->header.arcount)); - } - - if (nmb->header.qdcount) - { - DEBUGADD( 4, ( " question: q_name=%s q_type=%d q_class=%d\n", - nmb_namestr(&nmb->question.question_name), - nmb->question.question_type, - nmb->question.question_class) ); - } - - if (nmb->answers && nmb->header.ancount) - { - debug_nmb_res_rec(nmb->answers,"answers"); - } - if (nmb->nsrecs && nmb->header.nscount) - { - debug_nmb_res_rec(nmb->nsrecs,"nsrecs"); - } - if (nmb->additional && nmb->header.arcount) - { - debug_nmb_res_rec(nmb->additional,"additional"); - } -} - -/******************************************************************* - handle "compressed" name pointers - ******************************************************************/ -static BOOL handle_name_ptrs(uint8_t *ubuf,int *offset,int length, - BOOL *got_pointer,int *ret) -{ - int loop_count=0; - - while ((ubuf[*offset] & 0xC0) == 0xC0) { - if (!*got_pointer) (*ret) += 2; - (*got_pointer)=True; - (*offset) = ((ubuf[*offset] & ~0xC0)<<8) | ubuf[(*offset)+1]; - if (loop_count++ == 10 || (*offset) < 0 || (*offset)>(length-2)) { - return(False); - } - } - return(True); -} - -/******************************************************************* - parse a nmb name from "compressed" format to something readable - return the space taken by the name, or 0 if the name is invalid - ******************************************************************/ -static int parse_nmb_name(char *inbuf,int ofs,int length, struct nmb_name *name) -{ - int m,n=0; - uint8_t *ubuf = (uint8_t *)inbuf; - int ret = 0; - BOOL got_pointer=False; - int loop_count=0; - int offset = ofs; - - if (length - offset < 2) - return(0); - - /* handle initial name pointers */ - if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret)) - return(0); - - m = ubuf[offset]; - - if (!m) - return(0); - if ((m & 0xC0) || offset+m+2 > length) - return(0); - - memset((char *)name,'\0',sizeof(*name)); - - /* the "compressed" part */ - if (!got_pointer) - ret += m + 2; - offset++; - while (m > 0) { - uint8_t c1,c2; - c1 = ubuf[offset++]-'A'; - c2 = ubuf[offset++]-'A'; - if ((c1 & 0xF0) || (c2 & 0xF0) || (n > sizeof(name->name)-1)) - return(0); - name->name[n++] = (c1<<4) | c2; - m -= 2; - } - name->name[n] = 0; - - if (n==16) { - /* parse out the name type, - its always in the 16th byte of the name */ - name->name_type = ((uint8_t)name->name[15]) & 0xff; - - /* remove trailing spaces */ - name->name[15] = 0; - n = 14; - while (n && name->name[n]==' ') - name->name[n--] = 0; - } - - /* now the domain parts (if any) */ - n = 0; - while (ubuf[offset]) { - /* we can have pointers within the domain part as well */ - if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret)) - return(0); - - m = ubuf[offset]; - /* - * Don't allow null domain parts. - */ - if (!m) - return(0); - if (!got_pointer) - ret += m+1; - if (n) - name->scope[n++] = '.'; - if (m+2+offset>length || n+m+1>sizeof(name->scope)) - return(0); - offset++; - while (m--) - name->scope[n++] = (char)ubuf[offset++]; - - /* - * Watch for malicious loops. - */ - if (loop_count++ == 10) - return 0; - } - name->scope[n++] = 0; - - return(ret); -} - - -/******************************************************************* - put a compressed nmb name into a buffer. return the length of the - compressed name - - compressed names are really weird. The "compression" doubles the - size. The idea is that it also means that compressed names conform - to the doman name system. See RFC1002. - ******************************************************************/ -static int put_nmb_name(char *buf,int offset,struct nmb_name *name) -{ - int ret,m; - fstring buf1; - char *p; - - if (strcmp(name->name,"*") == 0) { - /* special case for wildcard name */ - memset(buf1,'\0',20); - buf1[0] = '*'; - buf1[15] = name->name_type; - } else { - slprintf(buf1, sizeof(buf1) - 1,"%-15.15s%c",name->name,name->name_type); - } - - buf[offset] = 0x20; - - ret = 34; - - for (m=0;m<16;m++) { - buf[offset+1+2*m] = 'A' + ((buf1[m]>>4)&0xF); - buf[offset+2+2*m] = 'A' + (buf1[m]&0xF); - } - offset += 33; - - buf[offset] = 0; - - if (name->scope[0]) { - /* XXXX this scope handling needs testing */ - ret += strlen(name->scope) + 1; - pstrcpy(&buf[offset+1],name->scope); - - p = &buf[offset+1]; - while ((p = strchr_m(p,'.'))) { - buf[offset] = PTR_DIFF(p,&buf[offset+1]); - offset += (buf[offset] + 1); - p = &buf[offset+1]; - } - buf[offset] = strlen(&buf[offset+1]); - } - - return(ret); -} - -/******************************************************************* - useful for debugging messages - ******************************************************************/ -char *nmb_namestr(struct nmb_name *n) -{ - static int i=0; - static fstring ret[4]; - char *p = ret[i]; - - if (!n->scope[0]) - slprintf(p,sizeof(fstring)-1, "%s<%02x>",n->name,n->name_type); - else - slprintf(p,sizeof(fstring)-1, "%s<%02x>.%s",n->name,n->name_type,n->scope); - - i = (i+1)%4; - return(p); -} - -/******************************************************************* - allocate and parse some resource records - ******************************************************************/ -static BOOL parse_alloc_res_rec(char *inbuf,int *offset,int length, - struct res_rec **recs, int count) -{ - int i; - *recs = malloc_array_p(struct res_rec, count); - if (!*recs) return(False); - - memset((char *)*recs,'\0',sizeof(**recs)*count); - - for (i=0;i<count;i++) { - int l = parse_nmb_name(inbuf,*offset,length,&(*recs)[i].rr_name); - (*offset) += l; - if (!l || (*offset)+10 > length) { - SAFE_FREE(*recs); - return(False); - } - (*recs)[i].rr_type = RSVAL(inbuf,(*offset)); - (*recs)[i].rr_class = RSVAL(inbuf,(*offset)+2); - (*recs)[i].ttl = RIVAL(inbuf,(*offset)+4); - (*recs)[i].rdlength = RSVAL(inbuf,(*offset)+8); - (*offset) += 10; - if ((*recs)[i].rdlength>sizeof((*recs)[i].rdata) || - (*offset)+(*recs)[i].rdlength > length) { - SAFE_FREE(*recs); - return(False); - } - memcpy((*recs)[i].rdata,inbuf+(*offset),(*recs)[i].rdlength); - (*offset) += (*recs)[i].rdlength; - } - return(True); -} - -/******************************************************************* - put a resource record into a packet - ******************************************************************/ -static int put_res_rec(char *buf,int offset,struct res_rec *recs,int count) -{ - int ret=0; - int i; - - for (i=0;i<count;i++) { - int l = put_nmb_name(buf,offset,&recs[i].rr_name); - offset += l; - ret += l; - RSSVAL(buf,offset,recs[i].rr_type); - RSSVAL(buf,offset+2,recs[i].rr_class); - RSIVAL(buf,offset+4,recs[i].ttl); - RSSVAL(buf,offset+8,recs[i].rdlength); - memcpy(buf+offset+10,recs[i].rdata,recs[i].rdlength); - offset += 10+recs[i].rdlength; - ret += 10+recs[i].rdlength; - } - - return(ret); -} - -/******************************************************************* - put a compressed name pointer record into a packet - ******************************************************************/ -static int put_compressed_name_ptr(uint8_t *buf,int offset,struct res_rec *rec,int ptr_offset) -{ - int ret=0; - buf[offset] = (0xC0 | ((ptr_offset >> 8) & 0xFF)); - buf[offset+1] = (ptr_offset & 0xFF); - offset += 2; - ret += 2; - RSSVAL(buf,offset,rec->rr_type); - RSSVAL(buf,offset+2,rec->rr_class); - RSIVAL(buf,offset+4,rec->ttl); - RSSVAL(buf,offset+8,rec->rdlength); - memcpy(buf+offset+10,rec->rdata,rec->rdlength); - offset += 10+rec->rdlength; - ret += 10+rec->rdlength; - - return(ret); -} - -/******************************************************************* - parse a dgram packet. Return False if the packet can't be parsed - or is invalid for some reason, True otherwise - - this is documented in section 4.4.1 of RFC1002 - ******************************************************************/ -static BOOL parse_dgram(char *inbuf,int length,struct dgram_packet *dgram) -{ - int offset; - int flags; - - memset((char *)dgram,'\0',sizeof(*dgram)); - - if (length < 14) return(False); - - dgram->header.msg_type = CVAL(inbuf,0); - flags = CVAL(inbuf,1); - dgram->header.flags.node_type = (enum node_type)((flags>>2)&3); - if (flags & 1) dgram->header.flags.more = True; - if (flags & 2) dgram->header.flags.first = True; - dgram->header.dgm_id = RSVAL(inbuf,2); - putip((char *)&dgram->header.source_ip,inbuf+4); - dgram->header.source_port = RSVAL(inbuf,8); - dgram->header.dgm_length = RSVAL(inbuf,10); - dgram->header.packet_offset = RSVAL(inbuf,12); - - offset = 14; - - if (dgram->header.msg_type == 0x10 || - dgram->header.msg_type == 0x11 || - dgram->header.msg_type == 0x12) { - offset += parse_nmb_name(inbuf,offset,length,&dgram->source_name); - offset += parse_nmb_name(inbuf,offset,length,&dgram->dest_name); - } - - if (offset >= length || (length-offset > sizeof(dgram->data))) - return(False); - - dgram->datasize = length-offset; - memcpy(dgram->data,inbuf+offset,dgram->datasize); - - return(True); -} - - -/******************************************************************* - parse a nmb packet. Return False if the packet can't be parsed - or is invalid for some reason, True otherwise - ******************************************************************/ -static BOOL parse_nmb(char *inbuf,int length,struct nmb_packet *nmb) -{ - int nm_flags,offset; - - memset((char *)nmb,'\0',sizeof(*nmb)); - - if (length < 12) return(False); - - /* parse the header */ - nmb->header.name_trn_id = RSVAL(inbuf,0); - - DEBUG(10,("parse_nmb: packet id = %d\n", nmb->header.name_trn_id)); - - nmb->header.opcode = (CVAL(inbuf,2) >> 3) & 0xF; - nmb->header.response = ((CVAL(inbuf,2)>>7)&1)?True:False; - nm_flags = ((CVAL(inbuf,2) & 0x7) << 4) + (CVAL(inbuf,3)>>4); - nmb->header.nm_flags.bcast = (nm_flags&1)?True:False; - nmb->header.nm_flags.recursion_available = (nm_flags&8)?True:False; - nmb->header.nm_flags.recursion_desired = (nm_flags&0x10)?True:False; - nmb->header.nm_flags.trunc = (nm_flags&0x20)?True:False; - nmb->header.nm_flags.authoritative = (nm_flags&0x40)?True:False; - nmb->header.rcode = CVAL(inbuf,3) & 0xF; - nmb->header.qdcount = RSVAL(inbuf,4); - nmb->header.ancount = RSVAL(inbuf,6); - nmb->header.nscount = RSVAL(inbuf,8); - nmb->header.arcount = RSVAL(inbuf,10); - - if (nmb->header.qdcount) { - offset = parse_nmb_name(inbuf,12,length,&nmb->question.question_name); - if (!offset) return(False); - - if (length - (12+offset) < 4) return(False); - nmb->question.question_type = RSVAL(inbuf,12+offset); - nmb->question.question_class = RSVAL(inbuf,12+offset+2); - - offset += 12+4; - } else { - offset = 12; - } - - /* and any resource records */ - if (nmb->header.ancount && - !parse_alloc_res_rec(inbuf,&offset,length,&nmb->answers, - nmb->header.ancount)) - return(False); - - if (nmb->header.nscount && - !parse_alloc_res_rec(inbuf,&offset,length,&nmb->nsrecs, - nmb->header.nscount)) - return(False); - - if (nmb->header.arcount && - !parse_alloc_res_rec(inbuf,&offset,length,&nmb->additional, - nmb->header.arcount)) - return(False); - - return(True); -} - -/******************************************************************* - 'Copy constructor' for an nmb packet - ******************************************************************/ -static struct packet_struct *copy_nmb_packet(struct packet_struct *packet) -{ - struct nmb_packet *nmb; - struct nmb_packet *copy_nmb; - struct packet_struct *pkt_copy; - - if(( pkt_copy = malloc_p(struct packet_struct)) == NULL) - { - DEBUG(0,("copy_nmb_packet: malloc fail.\n")); - return NULL; - } - - /* Structure copy of entire thing. */ - - *pkt_copy = *packet; - - /* Ensure this copy is not locked. */ - pkt_copy->locked = False; - - /* Ensure this copy has no resource records. */ - nmb = &packet->packet.nmb; - copy_nmb = &pkt_copy->packet.nmb; - - copy_nmb->answers = NULL; - copy_nmb->nsrecs = NULL; - copy_nmb->additional = NULL; - - /* Now copy any resource records. */ - - if (nmb->answers) - { - if((copy_nmb->answers = malloc_array_p(struct res_rec, nmb->header.ancount)) == NULL) - goto free_and_exit; - memcpy((char *)copy_nmb->answers, (char *)nmb->answers, - nmb->header.ancount * sizeof(struct res_rec)); - } - if (nmb->nsrecs) - { - if((copy_nmb->nsrecs = malloc_array_p(struct res_rec, nmb->header.nscount)) == NULL) - goto free_and_exit; - memcpy((char *)copy_nmb->nsrecs, (char *)nmb->nsrecs, - nmb->header.nscount * sizeof(struct res_rec)); - } - if (nmb->additional) - { - if((copy_nmb->additional = malloc_array_p(struct res_rec, nmb->header.arcount)) == NULL) - goto free_and_exit; - memcpy((char *)copy_nmb->additional, (char *)nmb->additional, - nmb->header.arcount * sizeof(struct res_rec)); - } - - return pkt_copy; - -free_and_exit: - - SAFE_FREE(copy_nmb->answers); - SAFE_FREE(copy_nmb->nsrecs); - SAFE_FREE(copy_nmb->additional); - SAFE_FREE(pkt_copy); - - DEBUG(0,("copy_nmb_packet: malloc fail in resource records.\n")); - return NULL; -} - -/******************************************************************* - 'Copy constructor' for a dgram packet - ******************************************************************/ -static struct packet_struct *copy_dgram_packet(struct packet_struct *packet) -{ - struct packet_struct *pkt_copy; - - if(( pkt_copy = malloc_p(struct packet_struct)) == NULL) - { - DEBUG(0,("copy_dgram_packet: malloc fail.\n")); - return NULL; - } - - /* Structure copy of entire thing. */ - - *pkt_copy = *packet; - - /* Ensure this copy is not locked. */ - pkt_copy->locked = False; - - /* There are no additional pointers in a dgram packet, - we are finished. */ - return pkt_copy; -} - -/******************************************************************* - 'Copy constructor' for a generic packet - ******************************************************************/ -struct packet_struct *copy_packet(struct packet_struct *packet) -{ - if(packet->packet_type == NMB_PACKET) - return copy_nmb_packet(packet); - else if (packet->packet_type == DGRAM_PACKET) - return copy_dgram_packet(packet); - return NULL; -} - -/******************************************************************* - free up any resources associated with an nmb packet - ******************************************************************/ -static void free_nmb_packet(struct nmb_packet *nmb) -{ - SAFE_FREE(nmb->answers); - SAFE_FREE(nmb->nsrecs); - SAFE_FREE(nmb->additional); -} - -/******************************************************************* - free up any resources associated with a dgram packet - ******************************************************************/ -static void free_dgram_packet(struct dgram_packet *nmb) -{ - /* We have nothing to do for a dgram packet. */ -} - -/******************************************************************* - free up any resources associated with a packet - ******************************************************************/ -void free_packet(struct packet_struct *packet) -{ - if (packet->locked) - return; - if (packet->packet_type == NMB_PACKET) - free_nmb_packet(&packet->packet.nmb); - else if (packet->packet_type == DGRAM_PACKET) - free_dgram_packet(&packet->packet.dgram); - ZERO_STRUCTPN(packet); - SAFE_FREE(packet); -} - -/******************************************************************* -parse a packet buffer into a packet structure - ******************************************************************/ -struct packet_struct *parse_packet(char *buf,int length, - enum packet_type packet_type) -{ - struct packet_struct *p; - BOOL ok=False; - - p = malloc_p(struct packet_struct); - if (!p) return(NULL); - - p->next = NULL; - p->prev = NULL; - p->locked = False; - p->timestamp = time(NULL); - p->packet_type = packet_type; - - switch (packet_type) { - case NMB_PACKET: - ok = parse_nmb(buf,length,&p->packet.nmb); - break; - - case DGRAM_PACKET: - ok = parse_dgram(buf,length,&p->packet.dgram); - break; - } - - if (!ok) { - free_packet(p); - return NULL; - } - - return p; -} - -/******************************************************************* - read a packet from a socket and parse it, returning a packet ready - to be used or put on the queue. This assumes a UDP socket - ******************************************************************/ -struct packet_struct *read_packet(int fd,enum packet_type packet_type) -{ - struct packet_struct *packet; - char buf[MAX_DGRAM_SIZE]; - int length; - struct ipv4_addr addr; - int port; - - length = read_udp_socket(fd, buf, sizeof(buf), &addr, &port); - if (length < MIN_DGRAM_SIZE) return(NULL); - - packet = parse_packet(buf, length, packet_type); - if (!packet) return NULL; - - packet->fd = fd; - packet->ip = addr; - packet->port = port; - - DEBUG(5,("Received a packet of len %d from (%s) port %d\n", - length, sys_inet_ntoa(packet->ip), packet->port)); - - return packet; -} - - -/******************************************************************* - send a udp packet on a already open socket - ******************************************************************/ -static BOOL send_udp(int fd,char *buf,int len,struct ipv4_addr ip,int port) -{ - BOOL ret = False; - int i; - struct sockaddr_in sock_out; - - /* set the address and port */ - memset((char *)&sock_out,'\0',sizeof(sock_out)); - putip((char *)&sock_out.sin_addr,(char *)&ip); - sock_out.sin_port = htons( port ); - sock_out.sin_family = AF_INET; - - DEBUG( 5, ( "Sending a packet of len %d to (%s) on port %d\n", - len, sys_inet_ntoa(ip), port ) ); - - /* - * Patch to fix asynch error notifications from Linux kernel. - */ - - for (i = 0; i < 5; i++) { - ret = (sendto(fd,buf,len,0,(struct sockaddr *)&sock_out, sizeof(sock_out)) >= 0); - if (ret || errno != ECONNREFUSED) - break; - } - - if (!ret) - DEBUG(0,("Packet send failed to %s(%d) ERRNO=%s\n", - sys_inet_ntoa(ip),port,strerror(errno))); - - return(ret); -} - -/******************************************************************* - build a dgram packet ready for sending - - XXXX This currently doesn't handle packets too big for one - datagram. It should split them and use the packet_offset, more and - first flags to handle the fragmentation. Yuck. - - [...but it isn't clear that we would ever need to send a - a fragmented NBT Datagram. The IP layer does its own - fragmentation to ensure that messages can fit into the path - MTU. It *is* important to be able to receive and rebuild - fragmented NBT datagrams, just in case someone out there - really has implemented this 'feature'. crh -)------ ] - - ******************************************************************/ -static int build_dgram(char *buf,struct packet_struct *p) -{ - struct dgram_packet *dgram = &p->packet.dgram; - uint8_t *ubuf = (uint8_t *)buf; - int offset=0; - - /* put in the header */ - ubuf[0] = dgram->header.msg_type; - ubuf[1] = (((int)dgram->header.flags.node_type)<<2); - if (dgram->header.flags.more) ubuf[1] |= 1; - if (dgram->header.flags.first) ubuf[1] |= 2; - RSSVAL(ubuf,2,dgram->header.dgm_id); - putip(ubuf+4,(char *)&dgram->header.source_ip); - RSSVAL(ubuf,8,dgram->header.source_port); - RSSVAL(ubuf,12,dgram->header.packet_offset); - - offset = 14; - - if (dgram->header.msg_type == 0x10 || - dgram->header.msg_type == 0x11 || - dgram->header.msg_type == 0x12) { - offset += put_nmb_name((char *)ubuf,offset,&dgram->source_name); - offset += put_nmb_name((char *)ubuf,offset,&dgram->dest_name); - } - - memcpy(ubuf+offset,dgram->data,dgram->datasize); - offset += dgram->datasize; - - /* automatically set the dgm_length - * NOTE: RFC1002 says the dgm_length does *not* - * include the fourteen-byte header. crh - */ - dgram->header.dgm_length = (offset - 14); - RSSVAL(ubuf,10,dgram->header.dgm_length); - - return(offset); -} - -/******************************************************************* - Build a nmb name -*******************************************************************/ - -void make_nmb_name( struct nmb_name *n, const char *name, int type) -{ - memset( (char *)n, '\0', sizeof(struct nmb_name) ); - push_ascii(n->name, name, 16, STR_TERMINATE|STR_UPPER); - n->name_type = (uint_t)type & 0xFF; - StrnCpy( n->scope, lp_netbios_scope(), 63 ); - strupper( n->scope ); -} - -/******************************************************************* - Compare two nmb names - ******************************************************************/ - -BOOL nmb_name_equal(struct nmb_name *n1, struct nmb_name *n2) -{ - return ((n1->name_type == n2->name_type) && - strequal(n1->name ,n2->name ) && - strequal(n1->scope,n2->scope)); -} - -/******************************************************************* - build a nmb packet ready for sending - - XXXX this currently relies on not being passed something that expands - to a packet too big for the buffer. Eventually this should be - changed to set the trunc bit so the receiver can request the rest - via tcp (when that becomes supported) - ******************************************************************/ -static int build_nmb(char *buf,struct packet_struct *p) -{ - struct nmb_packet *nmb = &p->packet.nmb; - uint8_t *ubuf = (uint8_t *)buf; - int offset=0; - - /* put in the header */ - RSSVAL(ubuf,offset,nmb->header.name_trn_id); - ubuf[offset+2] = (nmb->header.opcode & 0xF) << 3; - if (nmb->header.response) ubuf[offset+2] |= (1<<7); - if (nmb->header.nm_flags.authoritative && - nmb->header.response) ubuf[offset+2] |= 0x4; - if (nmb->header.nm_flags.trunc) ubuf[offset+2] |= 0x2; - if (nmb->header.nm_flags.recursion_desired) ubuf[offset+2] |= 0x1; - if (nmb->header.nm_flags.recursion_available && - nmb->header.response) ubuf[offset+3] |= 0x80; - if (nmb->header.nm_flags.bcast) ubuf[offset+3] |= 0x10; - ubuf[offset+3] |= (nmb->header.rcode & 0xF); - - RSSVAL(ubuf,offset+4,nmb->header.qdcount); - RSSVAL(ubuf,offset+6,nmb->header.ancount); - RSSVAL(ubuf,offset+8,nmb->header.nscount); - RSSVAL(ubuf,offset+10,nmb->header.arcount); - - offset += 12; - if (nmb->header.qdcount) { - /* XXXX this doesn't handle a qdcount of > 1 */ - offset += put_nmb_name((char *)ubuf,offset,&nmb->question.question_name); - RSSVAL(ubuf,offset,nmb->question.question_type); - RSSVAL(ubuf,offset+2,nmb->question.question_class); - offset += 4; - } - - if (nmb->header.ancount) - offset += put_res_rec((char *)ubuf,offset,nmb->answers, - nmb->header.ancount); - - if (nmb->header.nscount) - offset += put_res_rec((char *)ubuf,offset,nmb->nsrecs, - nmb->header.nscount); - - /* - * The spec says we must put compressed name pointers - * in the following outgoing packets : - * NAME_REGISTRATION_REQUEST, NAME_REFRESH_REQUEST, - * NAME_RELEASE_REQUEST. - */ - - if((nmb->header.response == False) && - ((nmb->header.opcode == NMB_NAME_REG_OPCODE) || - (nmb->header.opcode == NMB_NAME_RELEASE_OPCODE) || - (nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_8) || - (nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_9) || - (nmb->header.opcode == NMB_NAME_MULTIHOMED_REG_OPCODE)) && - (nmb->header.arcount == 1)) { - - offset += put_compressed_name_ptr(ubuf,offset,nmb->additional,12); - - } else if (nmb->header.arcount) { - offset += put_res_rec((char *)ubuf,offset,nmb->additional, - nmb->header.arcount); - } - return(offset); -} - - -/******************************************************************* -linearise a packet - ******************************************************************/ -int build_packet(char *buf, struct packet_struct *p) -{ - int len = 0; - - switch (p->packet_type) { - case NMB_PACKET: - len = build_nmb(buf,p); - break; - - case DGRAM_PACKET: - len = build_dgram(buf,p); - break; - } - - return len; -} - -/******************************************************************* - send a packet_struct - ******************************************************************/ -BOOL send_packet(struct packet_struct *p) -{ - char buf[1024]; - int len=0; - - memset(buf,'\0',sizeof(buf)); - - len = build_packet(buf, p); - - if (!len) return(False); - - return(send_udp(p->fd,buf,len,p->ip,p->port)); -} - -/**************************************************************************** - receive a packet with timeout on a open UDP filedescriptor - The timeout is in milliseconds - ***************************************************************************/ -struct packet_struct *receive_packet(int fd,enum packet_type type,int t) -{ - fd_set fds; - struct timeval timeout; - int ret; - - FD_ZERO(&fds); - FD_SET(fd,&fds); - timeout.tv_sec = t/1000; - timeout.tv_usec = 1000*(t%1000); - - if ((ret = sys_select_intr(fd+1,&fds,NULL,NULL,&timeout)) == -1) { - /* errno should be EBADF or EINVAL. */ - DEBUG(0,("select returned -1, errno = %s (%d)\n", strerror(errno), errno)); - return NULL; - } - - if (ret == 0) /* timeout */ - return NULL; - - if (FD_ISSET(fd,&fds)) - return(read_packet(fd,type)); - - return(NULL); -} - - -/**************************************************************************** - receive a UDP/137 packet either via UDP or from the unexpected packet - queue. The packet must be a reply packet and have the specified trn_id - The timeout is in milliseconds - ***************************************************************************/ -struct packet_struct *receive_nmb_packet(int fd, int t, int trn_id) -{ - struct packet_struct *p; - - p = receive_packet(fd, NMB_PACKET, t); - - if (p && p->packet.nmb.header.response && - p->packet.nmb.header.name_trn_id == trn_id) { - return p; - } - if (p) free_packet(p); - - /* try the unexpected packet queue */ - return receive_unexpected(NMB_PACKET, trn_id, NULL); -} - -/**************************************************************************** - receive a UDP/138 packet either via UDP or from the unexpected packet - queue. The packet must be a reply packet and have the specified mailslot name - The timeout is in milliseconds - ***************************************************************************/ -struct packet_struct *receive_dgram_packet(int fd, int t, const char *mailslot_name) -{ - struct packet_struct *p; - - p = receive_packet(fd, DGRAM_PACKET, t); - - if (p && match_mailslot_name(p, mailslot_name)) { - return p; - } - if (p) free_packet(p); - - /* try the unexpected packet queue */ - return receive_unexpected(DGRAM_PACKET, 0, mailslot_name); -} - - -/**************************************************************************** - see if a datagram has the right mailslot name -***************************************************************************/ -BOOL match_mailslot_name(struct packet_struct *p, const char *mailslot_name) -{ - struct dgram_packet *dgram = &p->packet.dgram; - char *buf; - - buf = &dgram->data[0]; - buf -= 4; - - buf = smb_buf(buf); - - if (memcmp(buf, mailslot_name, strlen(mailslot_name)+1) == 0) { - return True; - } - - return False; -} - - -/**************************************************************************** -return the number of bits that match between two 4 character buffers - ***************************************************************************/ -int matching_quad_bits(uint8_t *p1, uint8_t *p2) -{ - int i, j, ret = 0; - for (i=0; i<4; i++) { - if (p1[i] != p2[i]) break; - ret += 8; - } - - if (i==4) return ret; - - for (j=0; j<8; j++) { - if ((p1[i] & (1<<(7-j))) != (p2[i] & (1<<(7-j)))) break; - ret++; - } - - return ret; -} - - -static uint8_t sort_ip[4]; - -/**************************************************************************** -compare two query reply records - ***************************************************************************/ -static int name_query_comp(uint8_t *p1, uint8_t *p2) -{ - return matching_quad_bits(p2+2, sort_ip) - matching_quad_bits(p1+2, sort_ip); -} - -/**************************************************************************** -sort a set of 6 byte name query response records so that the IPs that -have the most leading bits in common with the specified address come first - ***************************************************************************/ -void sort_query_replies(char *data, int n, struct ipv4_addr ip) -{ - if (n <= 1) return; - - putip(sort_ip, (char *)&ip); - - qsort(data, n, 6, QSORT_CAST name_query_comp); -} - - -#define TRUNCATE_NETBIOS_NAME 1 - -/******************************************************************* - convert, possibly using a stupid microsoft-ism which has destroyed - the transport independence of netbios (for CIFS vendors that usually - use the Win95-type methods, not for NT to NT communication, which uses - DCE/RPC and therefore full-length unicode strings...) a dns name into - a netbios name. - - the netbios name (NOT necessarily null-terminated) is truncated to 15 - characters. - - ******************************************************************/ -char *dns_to_netbios_name(char *dns_name) -{ - static char netbios_name[16]; - int i; - StrnCpy(netbios_name, dns_name, 15); - netbios_name[15] = 0; - -#ifdef TRUNCATE_NETBIOS_NAME - /* ok. this is because of a stupid microsoft-ism. if the called host - name contains a '.', microsoft clients expect you to truncate the - netbios name up to and including the '.' this even applies, by - mistake, to workgroup (domain) names, which is _really_ daft. - */ - for (i = 15; i >= 0; i--) - { - if (netbios_name[i] == '.') - { - netbios_name[i] = 0; - break; - } - } -#endif /* TRUNCATE_NETBIOS_NAME */ - - return netbios_name; -} - - -/**************************************************************************** -interpret the weird netbios "name". Return the name type -****************************************************************************/ -static int name_interpret(char *in,char *out) -{ - int ret; - int len = (*in++) / 2; - - *out=0; - - if (len > 30 || len<1) return(0); - - while (len--) - { - if (in[0] < 'A' || in[0] > 'P' || in[1] < 'A' || in[1] > 'P') { - *out = 0; - return(0); - } - *out = ((in[0]-'A')<<4) + (in[1]-'A'); - in += 2; - out++; - } - *out = 0; - ret = out[-1]; - -#ifdef NETBIOS_SCOPE - /* Handle any scope names */ - while(*in) - { - *out++ = '.'; /* Scope names are separated by periods */ - len = *(uint8_t *)in++; - StrnCpy(out, in, len); - out += len; - *out=0; - in += len; - } -#endif - return(ret); -} - - -/**************************************************************************** -return the number of bytes that would be occupied by the result of -name_mangle() -****************************************************************************/ -uint_t nbt_mangled_name_len(void) -{ - const char *scope = lp_netbios_scope(); - uint_t ret = 34; - if (scope && *scope) { - ret += strlen(scope) + 1; - } - return ret; -} - -/**************************************************************************** -mangle a name into netbios format - - Note: <Out> must be nbt_mangled_name_len() in length -****************************************************************************/ -int name_mangle(char *In, char *Out, char name_type) -{ - int i; - int c; - int len; - char buf[20]; - char *p = Out; - const char *scope = lp_netbios_scope(); - - /* Safely copy the input string, In, into buf[]. */ - memset( buf, 0, 20 ); - if (strcmp(In,"*") == 0) { - buf[0] = '*'; - } else { - slprintf( buf, sizeof(buf) - 1, "%-15.15s%c", In, name_type); - } - - /* Place the length of the first field into the output buffer. */ - p[0] = 32; - p++; - - /* Now convert the name to the rfc1001/1002 format. */ - for ( i = 0; i < 16; i++ ) { - c = toupper( buf[i] ); - p[i*2] = ( (c >> 4) & 0xF ) + 'A'; - p[(i*2)+1] = (c & 0xF) + 'A'; - } - p += 32; - p[0] = '\0'; - - if (!scope || !*scope) { - return name_len(Out); - } - - /* Add the scope string. */ - for (i = 0, len = 0; scope[i]; i++, len++) { - switch(scope[i]) { - case '.': - p[0] = len; - p += (len + 1); - len = -1; - break; - default: - p[len+1] = scope[i]; - break; - } - } - - p[0] = len; - if (len > 0) { - p[len+1] = 0; - } - - return name_len(Out); -} - -/**************************************************************************** -find a pointer to a netbios name -****************************************************************************/ -static char *name_ptr(char *buf,int ofs) -{ - uint8_t c = *(uint8_t *)(buf+ofs); - - if ((c & 0xC0) == 0xC0) - { - uint16_t l = RSVAL(buf, ofs) & 0x3FFF; - DEBUG(5,("name ptr to pos %d from %d is %s\n",l,ofs,buf+l)); - return(buf + l); - } - else - return(buf+ofs); -} - -/**************************************************************************** -extract a netbios name from a buf -****************************************************************************/ -int name_extract(char *buf,int ofs,char *name) -{ - char *p = name_ptr(buf,ofs); - int d = PTR_DIFF(p,buf+ofs); - pstrcpy(name,""); - if (d < -50 || d > 50) return(0); - return(name_interpret(p,name)); -} - -/**************************************************************************** -return the total storage length of a mangled name -****************************************************************************/ -int name_len(char *s1) -{ - /* NOTE: this argument _must_ be unsigned */ - uint8_t *s = (uint8_t *)s1; - int len; - - /* If the two high bits of the byte are set, return 2. */ - if (0xC0 == (*s & 0xC0)) - return(2); - - /* Add up the length bytes. */ - for (len = 1; (*s); s += (*s) + 1) { - len += *s + 1; - SMB_ASSERT(len < 80); - } - - return(len); -} /* name_len */ - - -/* - choose a name to use when calling a server in a NBT session request. - we use heuristics to see if the name we have been given is a IP - address, or a too-long name. If it is then use *SMBSERVER, or a - truncated name -*/ -void choose_called_name(struct nmb_name *n, const char *name, int type) -{ - if (is_ipaddress(name)) { - make_nmb_name(n, "*SMBSERVER", type); - return; - } - if (strlen(name) > 16) { - const char *p = strchr(name, '.'); - char name2[17]; - if (p - name > 16) { - make_nmb_name(n, "*SMBSERVER", type); - return; - } - strlcpy(name2, name, 1+(p-name)); - make_nmb_name(n, name2, type); - return; - } - - /* looks OK */ - make_nmb_name(n, name, type); -} diff --git a/source4/libcli/raw/clisocket.c b/source4/libcli/raw/clisocket.c index 0edb95e1a1..e981049535 100644 --- a/source4/libcli/raw/clisocket.c +++ b/source4/libcli/raw/clisocket.c @@ -326,10 +326,11 @@ resolve a hostname and connect ****************************************************************************/ BOOL smbcli_sock_connect_byname(struct smbcli_socket *sock, const char *host, int port) { - int name_type = 0x20; - struct ipv4_addr ip; - char *name, *p; + int name_type = NBT_NAME_SERVER; + const char *address; NTSTATUS status; + struct nbt_name nbt_name; + char *name, *p; name = talloc_strdup(sock, host); @@ -339,13 +340,18 @@ BOOL smbcli_sock_connect_byname(struct smbcli_socket *sock, const char *host, in *p = 0; } - if (!resolve_name(name, name, &ip, name_type)) { + nbt_name.name = name; + nbt_name.type = name_type; + nbt_name.scope = NULL; + + status = resolve_name(&nbt_name, sock, &address); + if (!NT_STATUS_IS_OK(status)) { return False; } sock->hostname = name; - status = smbcli_sock_connect(sock, sys_inet_ntoa(ip), port); + status = smbcli_sock_connect(sock, address, port); return NT_STATUS_IS_OK(status); } diff --git a/source4/libcli/raw/clitransport.c b/source4/libcli/raw/clitransport.c index e6d40639c6..918f18fa40 100644 --- a/source4/libcli/raw/clitransport.c +++ b/source4/libcli/raw/clitransport.c @@ -145,41 +145,52 @@ static void smbcli_transport_write_disable(struct smbcli_transport *transport) send a session request */ struct smbcli_request *smbcli_transport_connect_send(struct smbcli_transport *transport, - struct nmb_name *calling, - struct nmb_name *called) + struct nbt_name *calling, + struct nbt_name *called) { uint8_t *p; - int len = NBT_HDR_SIZE; struct smbcli_request *req; + DATA_BLOB calling_blob, called_blob; + TALLOC_CTX *tmp_ctx = talloc_new(transport); + NTSTATUS status; - if (called) { - transport->called = *called; - } + status = nbt_name_dup(transport, called, &transport->called); + if (!NT_STATUS_IS_OK(status)) goto failed; + + status = nbt_name_to_blob(tmp_ctx, &calling_blob, calling); + if (!NT_STATUS_IS_OK(status)) goto failed; + + status = nbt_name_to_blob(tmp_ctx, &called_blob, called); + if (!NT_STATUS_IS_OK(status)) goto failed; /* allocate output buffer */ req = smbcli_request_setup_nonsmb(transport, - NBT_HDR_SIZE + 2*nbt_mangled_name_len()); - if (req == NULL) return NULL; + NBT_HDR_SIZE + + calling_blob.length + called_blob.length); + if (req == NULL) goto failed; /* put in the destination name */ p = req->out.buffer + NBT_HDR_SIZE; - name_mangle(called->name, (char *)p, called->name_type); - len += name_len((char *)p); + memcpy(p, called_blob.data, called_blob.length); + p += called_blob.length; - /* and my name */ - p = req->out.buffer+len; - name_mangle(calling->name, (char *)p, calling->name_type); - len += name_len((char *)p); + memcpy(p, calling_blob.data, calling_blob.length); + p += calling_blob.length; - _smb_setlen(req->out.buffer,len-4); + _smb_setlen(req->out.buffer, PTR_DIFF(p, req->out.buffer)-4); SCVAL(req->out.buffer,0,0x81); if (!smbcli_request_send(req)) { smbcli_request_destroy(req); - return NULL; + goto failed; } + talloc_free(tmp_ctx); return req; + +failed: + talloc_free(tmp_ctx); + return NULL; } /* @@ -237,8 +248,8 @@ NTSTATUS smbcli_transport_connect_recv(struct smbcli_request *req) send a session request (if needed) */ BOOL smbcli_transport_connect(struct smbcli_transport *transport, - struct nmb_name *calling, - struct nmb_name *called) + struct nbt_name *calling, + struct nbt_name *called) { struct smbcli_request *req; NTSTATUS status; diff --git a/source4/libcli/raw/libcliraw.h b/source4/libcli/raw/libcliraw.h index 4047a5d369..d7414a237e 100644 --- a/source4/libcli/raw/libcliraw.h +++ b/source4/libcli/raw/libcliraw.h @@ -21,6 +21,7 @@ */ #include "request.h" +#include "librpc/gen_ndr/ndr_nbt.h" struct smbcli_tree; /* forward declare */ struct smbcli_request; /* forward declare */ @@ -151,7 +152,7 @@ struct smbcli_transport { /* remember the called name - some sub-protocols require us to know the server name */ - struct nmb_name called; + struct nbt_name called; /* a buffer for partially received SMB packets. */ struct { diff --git a/source4/libcli/resolve/bcast.c b/source4/libcli/resolve/bcast.c new file mode 100644 index 0000000000..b2d37fbfbb --- /dev/null +++ b/source4/libcli/resolve/bcast.c @@ -0,0 +1,163 @@ +/* + Unix SMB/CIFS implementation. + + broadcast name resolution module + + Copyright (C) Andrew Tridgell 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "system/network.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/nbt/libnbt.h" +#include "libcli/composite/composite.h" + +struct bcast_state { + struct nbt_name name; + struct nbt_name_socket *nbtsock; + int num_queries; + struct nbt_name_request **queries; + struct nbt_name_query *io_queries; + const char *reply_addr; +}; + +/* + handle events during broadcast name resolution +*/ +static void bcast_handler(struct nbt_name_request *req) +{ + struct smbcli_composite *c = talloc_get_type(req->async.private, + struct smbcli_composite); + struct bcast_state *state = talloc_get_type(c->private, struct bcast_state); + int i; + + for (i=0;i<state->num_queries;i++) { + if (req == state->queries[i]) break; + } + if (i == state->num_queries) { + /* not for us?! */ + c->status = NT_STATUS_INTERNAL_ERROR; + c->state = SMBCLI_REQUEST_ERROR; + goto done; + } + + c->status = nbt_name_query_recv(req, state, &state->io_queries[i]); + if (!NT_STATUS_IS_OK(c->status)) { + c->state = SMBCLI_REQUEST_ERROR; + } else { + c->state = SMBCLI_REQUEST_DONE; + state->reply_addr = talloc_steal(state, state->io_queries[i].out.reply_addr); + } + +done: + talloc_free(state->nbtsock); + if (c->async.fn) { + c->async.fn(c); + } +} + +/* + broadcast name resolution method - async send + */ +struct smbcli_composite *resolve_name_bcast_send(struct nbt_name *name, + struct event_context *event_ctx) +{ + struct smbcli_composite *c; + struct bcast_state *state; + int i; + NTSTATUS status; + + c = talloc_zero(NULL, struct smbcli_composite); + if (c == NULL) goto failed; + + state = talloc(c, struct bcast_state); + if (state == NULL) goto failed; + + status = nbt_name_dup(state, name, &state->name); + if (!NT_STATUS_IS_OK(status)) goto failed; + + state->nbtsock = nbt_name_socket_init(state, event_ctx); + if (state->nbtsock == NULL) goto failed; + + state->num_queries = iface_count(); + + state->io_queries = talloc_array(state, struct nbt_name_query, state->num_queries); + if (!state->io_queries) goto failed; + + state->queries = talloc_array(state, struct nbt_name_request *, state->num_queries); + if (!state->queries) goto failed; + + for (i=0;i<state->num_queries;i++) { + struct ipv4_addr *ip = iface_n_bcast(i); + const char *addr = sys_inet_ntoa(*ip); + if (!addr) goto failed; + + state->io_queries[i].in.name = state->name; + state->io_queries[i].in.dest_addr = talloc_strdup(state->io_queries, addr); + if (!state->io_queries[i].in.dest_addr) goto failed; + state->io_queries[i].in.broadcast = True; + state->io_queries[i].in.wins_lookup = False; + state->io_queries[i].in.timeout = lp_parm_int(-1, "nbt", "bcastTimeout", 5); + + state->queries[i] = nbt_name_query_send(state->nbtsock, &state->io_queries[i]); + if (!state->queries[i]) goto failed; + + state->queries[i]->async.fn = bcast_handler; + state->queries[i]->async.private = c; + } + + c->state = SMBCLI_REQUEST_SEND; + c->private = state; + c->event_ctx = state->nbtsock->event_ctx; + + return c; + +failed: + talloc_free(c); + return NULL; +} + +/* + broadcast name resolution method - recv side + */ +NTSTATUS resolve_name_bcast_recv(struct smbcli_composite *c, + TALLOC_CTX *mem_ctx, const char **reply_addr) +{ + NTSTATUS status; + + status = smb_composite_wait(c); + + if (NT_STATUS_IS_OK(status)) { + struct bcast_state *state = talloc_get_type(c->private, struct bcast_state); + *reply_addr = talloc_steal(mem_ctx, state->reply_addr); + } + + talloc_free(c); + return status; +} + +/* + broadcast name resolution method - sync call + */ +NTSTATUS resolve_name_bcast(struct nbt_name *name, + TALLOC_CTX *mem_ctx, + const char **reply_addr) +{ + struct smbcli_composite *c = resolve_name_bcast_send(name, NULL); + return resolve_name_bcast_recv(c, mem_ctx, reply_addr); +} + diff --git a/source4/libcli/resolve/resolve.c b/source4/libcli/resolve/resolve.c new file mode 100644 index 0000000000..e83b11c95e --- /dev/null +++ b/source4/libcli/resolve/resolve.c @@ -0,0 +1,51 @@ +/* + Unix SMB/CIFS implementation. + + general name resolution interface + + Copyright (C) Andrew Tridgell 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/composite/composite.h" + +/* + general name resolution - async send + */ +struct smbcli_composite *resolve_name_send(struct nbt_name *name, struct event_context *event_ctx) +{ + return resolve_name_bcast_send(name, event_ctx); +} + +/* + general name resolution method - recv side + */ +NTSTATUS resolve_name_recv(struct smbcli_composite *c, + TALLOC_CTX *mem_ctx, const char **reply_addr) +{ + return resolve_name_bcast_recv(c, mem_ctx, reply_addr); +} + +/* + general name resolution - sync call + */ +NTSTATUS resolve_name(struct nbt_name *name, TALLOC_CTX *mem_ctx, const char **reply_addr) +{ + struct smbcli_composite *c = resolve_name_send(name, NULL); + return resolve_name_recv(c, mem_ctx, reply_addr); +} diff --git a/source4/libcli/unexpected.c b/source4/libcli/unexpected.c deleted file mode 100644 index 264b9d7b33..0000000000 --- a/source4/libcli/unexpected.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - Unix SMB/CIFS implementation. - handle unexpected packets - Copyright (C) Andrew Tridgell 2000 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include "includes.h" - -static struct tdb_wrap *tdbd = NULL; - -/* the key type used in the unexpeceted packet database */ -struct unexpected_key { - enum packet_type packet_type; - time_t timestamp; - int count; -}; - - - -/**************************************************************************** - all unexpected packets are passed in here, to be stored in a unexpected - packet database. This allows nmblookup and other tools to receive packets - erroneoously sent to the wrong port by broken MS systems - **************************************************************************/ -void unexpected_packet(struct packet_struct *p) -{ - static int count; - TDB_DATA kbuf, dbuf; - struct unexpected_key key; - char buf[1024]; - int len=0; - - if (!tdbd) { - char *path = smbd_tmp_path(NULL, "unexpected.tdb"); - tdbd = tdb_wrap_open(NULL, path, 0, - TDB_DEFAULT, - O_RDWR | O_CREAT, 0644); - talloc_free(path); - if (!tdbd) { - return; - } - } - - memset(buf,'\0',sizeof(buf)); - - len = build_packet(buf, p); - - key.packet_type = p->packet_type; - key.timestamp = p->timestamp; - key.count = count++; - - kbuf.dptr = (char *)&key; - kbuf.dsize = sizeof(key); - dbuf.dptr = buf; - dbuf.dsize = len; - - tdb_store(tdbd->tdb, kbuf, dbuf, TDB_REPLACE); -} - - -static time_t lastt; - -/**************************************************************************** -delete the record if it is too old - **************************************************************************/ -static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state) -{ - struct unexpected_key key; - - memcpy(&key, kbuf.dptr, sizeof(key)); - - if (lastt - key.timestamp > NMBD_UNEXPECTED_TIMEOUT) { - tdb_delete(ttdb, kbuf); - } - - return 0; -} - - -/**************************************************************************** -delete all old unexpected packets - **************************************************************************/ -void clear_unexpected(time_t t) -{ - if (!tdbd) return; - - if ((lastt != 0) && (t < lastt + NMBD_UNEXPECTED_TIMEOUT)) - return; - - lastt = t; - - tdb_traverse(tdbd->tdb, traverse_fn, NULL); -} - - -static struct packet_struct *matched_packet; -static int match_id; -static enum packet_type match_type; -static const char *match_name; - -/**************************************************************************** -tdb traversal fn to find a matching 137 packet - **************************************************************************/ -static int traverse_match(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state) -{ - struct unexpected_key key; - struct packet_struct *p; - - memcpy(&key, kbuf.dptr, sizeof(key)); - - if (key.packet_type != match_type) return 0; - - p = parse_packet(dbuf.dptr, dbuf.dsize, match_type); - - if ((match_type == NMB_PACKET && - p->packet.nmb.header.name_trn_id == match_id) || - (match_type == DGRAM_PACKET && - match_mailslot_name(p, match_name))) { - matched_packet = p; - return -1; - } - - free_packet(p); - - return 0; -} - - -/**************************************************************************** -check for a particular packet in the unexpected packet queue - **************************************************************************/ -struct packet_struct *receive_unexpected(enum packet_type packet_type, int id, - const char *mailslot_name) -{ - struct tdb_wrap *tdb2; - char *path; - - path = smbd_tmp_path(NULL, "unexpected.tdb"); - tdb2 = tdb_wrap_open(NULL, path, 0, 0, O_RDONLY, 0); - talloc_free(path); - if (!tdb2) { - return NULL; - } - - matched_packet = NULL; - match_id = id; - match_type = packet_type; - match_name = mailslot_name; - - tdb_traverse(tdb2->tdb, traverse_match, NULL); - - talloc_free(tdb2); - - return matched_packet; -} diff --git a/source4/libnet/libnet_rpc.c b/source4/libnet/libnet_rpc.c index b4b33bf4c0..1f546d89a4 100644 --- a/source4/libnet/libnet_rpc.c +++ b/source4/libnet/libnet_rpc.c @@ -19,29 +19,34 @@ */ #include "includes.h" +#include "libcli/nbt/libnbt.h" #include "libnet/libnet.h" /* find a domain pdc generic */ -static NTSTATUS libnet_find_pdc_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_find_pdc *r) +static NTSTATUS libnet_find_pdc_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, + union libnet_find_pdc *r) { - BOOL ret; - struct ipv4_addr ip; + const char *address; + NTSTATUS status; + struct nbt_name name; if (is_ipaddress(r->generic.in.domain_name)) { r->generic.out.pdc_name = r->generic.in.domain_name; return NT_STATUS_OK; } - ret = get_pdc_ip(mem_ctx, r->generic.in.domain_name, &ip); - if (!ret) { - /* fallback to a workstation name */ - ret = resolve_name(mem_ctx, r->generic.in.domain_name, &ip, 0x20); - if (!ret) { - return NT_STATUS_NO_LOGON_SERVERS; - } + name.name = r->generic.in.domain_name; + name.type = NBT_NAME_PDC; + name.scope = NULL; + + status = resolve_name(&name, mem_ctx, &address); + if (!NT_STATUS_IS_OK(status)) { + name.type = NBT_NAME_SERVER; + status = resolve_name(&name, mem_ctx, &address); } + NT_STATUS_NOT_OK_RETURN(status); - r->generic.out.pdc_name = talloc_strdup(mem_ctx, sys_inet_ntoa(ip)); + r->generic.out.pdc_name = talloc_strdup(mem_ctx, address); return NT_STATUS_OK; } diff --git a/source4/torture/rpc/xplogin.c b/source4/torture/rpc/xplogin.c index 6dcd456fdb..8acf3c4eb7 100644 --- a/source4/torture/rpc/xplogin.c +++ b/source4/torture/rpc/xplogin.c @@ -62,12 +62,15 @@ static NTSTATUS after_negprot(struct smbcli_transport **dst_transport, talloc_set_destructor(transport, destroy_transport); { - struct nmb_name calling; - struct nmb_name called; + struct nbt_name calling; + struct nbt_name called; /* send a NBT session request, if applicable */ - make_nmb_name(&calling, my_name, 0x0); - choose_called_name(&called, dest_host, 0x20); + calling.name = my_name; + calling.type = NBT_NAME_CLIENT; + calling.scope = NULL; + + nbt_choose_called_name(transport, &called, dest_host, NBT_NAME_SERVER); if (!smbcli_transport_connect(transport, &calling, &called)) { talloc_free(transport); diff --git a/source4/torture/torture.c b/source4/torture/torture.c index b2219c617c..63793b41da 100644 --- a/source4/torture/torture.c +++ b/source4/torture/torture.c @@ -44,12 +44,15 @@ BOOL torture_showall = False; static struct smbcli_state *open_nbt_connection(void) { - struct nmb_name called, calling; + struct nbt_name called, calling; struct smbcli_state *cli; const char *host = lp_parm_string(-1, "torture", "host"); - make_nmb_name(&calling, lp_netbios_name(), 0x0); - choose_called_name(&called, host, 0x20); + calling.name = lp_netbios_name(); + calling.type = NBT_NAME_CLIENT; + calling.scope = NULL; + + nbt_choose_called_name(NULL, &called, host, NBT_NAME_SERVER); cli = smbcli_state_init(NULL); if (!cli) { @@ -63,23 +66,9 @@ static struct smbcli_state *open_nbt_connection(void) } if (!smbcli_transport_establish(cli, &calling, &called)) { - /* - * Well, that failed, try *SMBSERVER ... - * However, we must reconnect as well ... - */ - if (!smbcli_socket_connect(cli, host)) { - printf("Failed to connect with %s\n", host); - return False; - } - - make_nmb_name(&called, "*SMBSERVER", 0x20); - if (!smbcli_transport_establish(cli, &calling, &called)) { - printf("%s rejected the session\n",host); - printf("We tried with a called name of %s & %s\n", - host, "*SMBSERVER"); - smbcli_shutdown(cli); - return NULL; - } + printf("%s rejected the session\n",host); + smbcli_shutdown(cli); + return NULL; } return cli; |