From f06e39e30866207162656801210d2f574166d4df Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 13 Apr 2005 05:07:04 +0000 Subject: r6321: added IDL and test suite for NBT dgram 'sam logon' request (sent by clients when a user tries to login) (This used to be commit 08ded62156b387457bc56b5910e1ddc813b375bd) --- source4/libcli/config.mk | 3 +- source4/libcli/dgram/libdgram.h | 15 +++++ source4/libcli/dgram/ntlogon.c | 117 +++++++++++++++++++++++++++++++++++++ source4/librpc/idl/nbt.idl | 45 +++++++++++++- source4/nbt_server/config.mk | 1 + source4/nbt_server/dgram/ntlogon.c | 76 ++++++++++++++++++++++++ source4/nbt_server/dgram/request.c | 1 + source4/torture/nbt/dgram.c | 112 ++++++++++++++++++++++++++++++++++- source4/torture/rpc/testjoin.c | 11 ++++ 9 files changed, 377 insertions(+), 4 deletions(-) create mode 100644 source4/libcli/dgram/ntlogon.c create mode 100644 source4/nbt_server/dgram/ntlogon.c diff --git a/source4/libcli/config.mk b/source4/libcli/config.mk index 56e923daa2..def7bd0f27 100644 --- a/source4/libcli/config.mk +++ b/source4/libcli/config.mk @@ -39,7 +39,8 @@ REQUIRED_SUBSYSTEMS = LIBNDR_RAW NDR_NBT SOCKET LIBCLI_COMPOSITE_BASE LIBEVENTS ADD_OBJ_FILES = \ libcli/dgram/dgramsocket.o \ libcli/dgram/mailslot.o \ - libcli/dgram/netlogon.o + libcli/dgram/netlogon.o \ + libcli/dgram/ntlogon.o NOPROTO=YES REQUIRED_SUBSYSTEMS = LIBCLI_NBT diff --git a/source4/libcli/dgram/libdgram.h b/source4/libcli/dgram/libdgram.h index 163cb1e37d..af278d2ab6 100644 --- a/source4/libcli/dgram/libdgram.h +++ b/source4/libcli/dgram/libdgram.h @@ -134,3 +134,18 @@ NTSTATUS dgram_mailslot_netlogon_parse(struct dgram_mailslot_handler *dgmslot, TALLOC_CTX *mem_ctx, struct nbt_dgram_packet *dgram, struct nbt_netlogon_packet *netlogon); + +NTSTATUS dgram_mailslot_ntlogon_send(struct nbt_dgram_socket *dgmsock, + struct nbt_name *dest_name, + const char *dest_address, + int dest_port, + struct nbt_name *src_name, + struct nbt_ntlogon_packet *request); +NTSTATUS dgram_mailslot_ntlogon_reply(struct nbt_dgram_socket *dgmsock, + struct nbt_dgram_packet *request, + const char *mailslot_name, + struct nbt_ntlogon_packet *reply); +NTSTATUS dgram_mailslot_ntlogon_parse(struct dgram_mailslot_handler *dgmslot, + TALLOC_CTX *mem_ctx, + struct nbt_dgram_packet *dgram, + struct nbt_ntlogon_packet *ntlogon); diff --git a/source4/libcli/dgram/ntlogon.c b/source4/libcli/dgram/ntlogon.c new file mode 100644 index 0000000000..7f18e8cec6 --- /dev/null +++ b/source4/libcli/dgram/ntlogon.c @@ -0,0 +1,117 @@ +/* + Unix SMB/CIFS implementation. + + handling for ntlogon dgram requests + + 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 "lib/events/events.h" +#include "dlinklist.h" +#include "libcli/nbt/libnbt.h" +#include "libcli/dgram/libdgram.h" +#include "lib/socket/socket.h" +#include "librpc/gen_ndr/ndr_nbt.h" + +/* + send a ntlogon mailslot request +*/ +NTSTATUS dgram_mailslot_ntlogon_send(struct nbt_dgram_socket *dgmsock, + struct nbt_name *dest_name, + const char *dest_address, + int dest_port, + struct nbt_name *src_name, + struct nbt_ntlogon_packet *request) +{ + NTSTATUS status; + DATA_BLOB blob; + TALLOC_CTX *tmp_ctx = talloc_new(dgmsock); + + status = ndr_push_struct_blob(&blob, tmp_ctx, request, + (ndr_push_flags_fn_t)ndr_push_nbt_ntlogon_packet); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(tmp_ctx); + return status; + } + + + status = dgram_mailslot_send(dgmsock, DGRAM_DIRECT_UNIQUE, + NBT_MAILSLOT_NTLOGON, + dest_name, dest_address, dest_port, + src_name, &blob); + talloc_free(tmp_ctx); + return status; +} + + +/* + send a ntlogon mailslot reply +*/ +NTSTATUS dgram_mailslot_ntlogon_reply(struct nbt_dgram_socket *dgmsock, + struct nbt_dgram_packet *request, + const char *mailslot_name, + struct nbt_ntlogon_packet *reply) +{ + NTSTATUS status; + DATA_BLOB blob; + TALLOC_CTX *tmp_ctx = talloc_new(dgmsock); + struct nbt_name myname; + + status = ndr_push_struct_blob(&blob, tmp_ctx, reply, + (ndr_push_flags_fn_t)ndr_push_nbt_ntlogon_packet); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(tmp_ctx); + return status; + } + + myname.name = lp_netbios_name(); + myname.type = NBT_NAME_CLIENT; + myname.scope = NULL; + + status = dgram_mailslot_send(dgmsock, DGRAM_DIRECT_UNIQUE, + mailslot_name, + &request->data.msg.source_name, + request->source, request->src_port, + &myname, &blob); + talloc_free(tmp_ctx); + return status; +} + + +/* + parse a ntlogon response. The packet must be a valid mailslot packet +*/ +NTSTATUS dgram_mailslot_ntlogon_parse(struct dgram_mailslot_handler *dgmslot, + TALLOC_CTX *mem_ctx, + struct nbt_dgram_packet *dgram, + struct nbt_ntlogon_packet *ntlogon) +{ + DATA_BLOB *data = &dgram->data.msg.body.smb.body.trans.data; + NTSTATUS status; + + status = ndr_pull_struct_blob(data, mem_ctx, ntlogon, + (ndr_pull_flags_fn_t)ndr_pull_nbt_ntlogon_packet); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("Failed to parse ntlogon packet of length %d\n", + data->length)); +#if 0 + file_save("ntlogon.dat", data->data, data->length); +#endif + } + return status; +} diff --git a/source4/librpc/idl/nbt.idl b/source4/librpc/idl/nbt.idl index c03f30333e..d7c89966f1 100644 --- a/source4/librpc/idl/nbt.idl +++ b/source4/librpc/idl/nbt.idl @@ -228,6 +228,7 @@ easier */ const string NBT_MAILSLOT_NETLOGON = "\\MAILSLOT\\NET\\NETLOGON"; + const string NBT_MAILSLOT_NTLOGON = "\\MAILSLOT\\NET\\NTLOGON"; const string NBT_MAILSLOT_GETDC = "\\MAILSLOT\\GETDC"; const string NBT_MAILSLOT_BROWSE = "\\MAILSLOT\\BROWSE"; @@ -326,6 +327,7 @@ } nbt_dgram_packet; + /*******************************************/ /* \MAILSLOT\NET\NETLOGON mailslot requests */ typedef enum { NETLOGON_QUERY_FOR_PDC = 0x7, @@ -376,7 +378,7 @@ uint32 db_count; nbt_db_change dbchange[db_count]; [value(ndr_size_dom_sid(&r->sid))] uint32 sid_size; - uint16 unknown; + [flag(NDR_ALIGN4)] DATA_BLOB _pad2; dom_sid sid; uint32 nt_version; uint16 lmnt_token; @@ -393,4 +395,45 @@ nbt_netlogon_command command; [switch_is(command)] nbt_netlogon_request req; } nbt_netlogon_packet; + + /*******************************************/ + /* \MAILSLOT\NET\NTLOGON mailslot requests */ + typedef enum { + NTLOGON_SAM_LOGON = 0x12, + NTLOGON_SAM_LOGON_REPLY = 0x13 + } nbt_ntlogon_command; + + typedef struct { + uint16 request_count; + nstring computer_name; + nstring user_name; + astring mailslot_name; + uint32 acct_control; + [value(ndr_size_dom_sid(&r->sid))] uint32 sid_size; + [flag(NDR_ALIGN4)] DATA_BLOB _pad; + dom_sid sid; + uint32 nt_version; + uint16 lmnt_token; + uint16 lm20_token; + } nbt_ntlogon_sam_logon; + + typedef struct { + nstring server; + nstring user_name; + nstring domain; + uint32 nt_version; + uint16 lmnt_token; + uint16 lm20_token; + } nbt_ntlogon_sam_logon_reply; + + typedef [nodiscriminant] union { + [case(NTLOGON_SAM_LOGON)] nbt_ntlogon_sam_logon logon; + [case(NTLOGON_SAM_LOGON_REPLY)] nbt_ntlogon_sam_logon_reply reply; + } nbt_ntlogon_request; + + typedef [flag(NDR_NOALIGN),public] struct { + nbt_ntlogon_command command; + [switch_is(command)] nbt_ntlogon_request req; + } nbt_ntlogon_packet; + } diff --git a/source4/nbt_server/config.mk b/source4/nbt_server/config.mk index 04a9dde1b0..7576bf3349 100644 --- a/source4/nbt_server/config.mk +++ b/source4/nbt_server/config.mk @@ -19,6 +19,7 @@ REQUIRED_SUBSYSTEMS = \ ADD_OBJ_FILES = \ nbt_server/dgram/request.o \ nbt_server/dgram/netlogon.o \ + nbt_server/dgram/ntlogon.o \ nbt_server/dgram/browse.o REQUIRED_SUBSYSTEMS = \ LIBCLI_DGRAM diff --git a/source4/nbt_server/dgram/ntlogon.c b/source4/nbt_server/dgram/ntlogon.c new file mode 100644 index 0000000000..d035c2f00a --- /dev/null +++ b/source4/nbt_server/dgram/ntlogon.c @@ -0,0 +1,76 @@ +/* + Unix SMB/CIFS implementation. + + NBT datagram ntlogon server + + 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 "dlinklist.h" +#include "nbt_server/nbt_server.h" +#include "smbd/service_task.h" +#include "lib/socket/socket.h" + +/* + handle incoming ntlogon mailslot requests +*/ +void nbtd_mailslot_ntlogon_handler(struct dgram_mailslot_handler *dgmslot, + struct nbt_dgram_packet *packet, + const char *src_address, int src_port) +{ + NTSTATUS status = NT_STATUS_NO_MEMORY; + struct nbtd_interface *iface = + talloc_get_type(dgmslot->private, struct nbtd_interface); + struct nbt_ntlogon_packet *ntlogon = + talloc(dgmslot, struct nbt_ntlogon_packet); + struct nbtd_iface_name *iname; + struct nbt_name *name = &packet->data.msg.dest_name; + + if (ntlogon == NULL) goto failed; + + /* + see if the we are listening on the destination netbios name + */ + iname = nbtd_find_iname(iface, name, 0); + if (iname == NULL) { + status = NT_STATUS_BAD_NETWORK_NAME; + goto failed; + } + + DEBUG(2,("ntlogon request to %s from %s:%d\n", + nbt_name_string(ntlogon, name), src_address, src_port)); + status = dgram_mailslot_ntlogon_parse(dgmslot, ntlogon, packet, ntlogon); + if (!NT_STATUS_IS_OK(status)) goto failed; + + NDR_PRINT_DEBUG(nbt_ntlogon_packet, ntlogon); + + switch (ntlogon->command) { + default: + DEBUG(2,("unknown ntlogon op %d from %s:%d\n", + ntlogon->command, src_address, src_port)); + break; + } + + talloc_free(ntlogon); + return; + +failed: + DEBUG(2,("nbtd ntlogon handler failed from %s:%d - %s\n", + src_address, src_port, nt_errstr(status))); + talloc_free(ntlogon); +} diff --git a/source4/nbt_server/dgram/request.c b/source4/nbt_server/dgram/request.c index 59b94bcecb..f59193bec5 100644 --- a/source4/nbt_server/dgram/request.c +++ b/source4/nbt_server/dgram/request.c @@ -34,6 +34,7 @@ static const struct { dgram_mailslot_handler_t handler; } mailslot_handlers[] = { { NBT_MAILSLOT_NETLOGON, nbtd_mailslot_netlogon_handler }, + { NBT_MAILSLOT_NTLOGON, nbtd_mailslot_ntlogon_handler }, { NBT_MAILSLOT_BROWSE, nbtd_mailslot_browse_handler } }; diff --git a/source4/torture/nbt/dgram.c b/source4/torture/nbt/dgram.c index b62c41b17d..14d98fc0c0 100644 --- a/source4/torture/nbt/dgram.c +++ b/source4/torture/nbt/dgram.c @@ -24,6 +24,7 @@ #include "libcli/nbt/libnbt.h" #include "libcli/dgram/libdgram.h" #include "librpc/gen_ndr/ndr_nbt.h" +#include "librpc/gen_ndr/ndr_samr.h" #include "lib/socket/socket.h" #include "lib/events/events.h" @@ -61,7 +62,7 @@ static BOOL nbt_test_netlogon(TALLOC_CTX *mem_ctx, { struct dgram_mailslot_handler *dgmslot; struct nbt_dgram_socket *dgmsock = nbt_dgram_socket_init(mem_ctx, NULL); - const char *myaddress = talloc_strdup(mem_ctx, iface_best_ip(address)); + const char *myaddress = talloc_strdup(dgmsock, iface_best_ip(address)); struct nbt_netlogon_packet logon; struct nbt_name myname; NTSTATUS status; @@ -116,6 +117,112 @@ failed: } +/* + reply handler for ntlogon request +*/ +static void ntlogon_handler(struct dgram_mailslot_handler *dgmslot, + struct nbt_dgram_packet *packet, + const char *src_address, int src_port) +{ + NTSTATUS status; + struct nbt_ntlogon_packet ntlogon; + int *replies = dgmslot->private; + + printf("ntlogon reply from %s:%d\n", src_address, src_port); + + status = dgram_mailslot_ntlogon_parse(dgmslot, dgmslot, packet, &ntlogon); + if (!NT_STATUS_IS_OK(status)) { + printf("Failed to parse ntlogon packet from %s:%d\n", + src_address, src_port); + return; + } + + NDR_PRINT_DEBUG(nbt_ntlogon_packet, &ntlogon); + + (*replies)++; +} + + +/* test UDP/138 ntlogon requests */ +static BOOL nbt_test_ntlogon(TALLOC_CTX *mem_ctx, + struct nbt_name name, const char *address) +{ + struct dgram_mailslot_handler *dgmslot; + struct nbt_dgram_socket *dgmsock = nbt_dgram_socket_init(mem_ctx, NULL); + const char *myaddress = talloc_strdup(dgmsock, iface_best_ip(address)); + struct nbt_ntlogon_packet logon; + struct nbt_name myname; + NTSTATUS status; + struct timeval tv = timeval_current(); + int replies = 0; + struct test_join *join_ctx; + const char *password; + const char *dom_sid; + + join_ctx = torture_join_domain(TEST_NAME, lp_workgroup(), + ACB_WSTRUST, &password); + if (join_ctx == NULL) { + printf("Failed to join domain %s as %s\n", lp_workgroup(), TEST_NAME); + talloc_free(dgmsock); + return False; + } + + dom_sid = torture_join_sid(join_ctx); + + /* try receiving replies on port 138 first, which will only + work if we are root and smbd/nmbd are not running - fall + back to listening on any port, which means replies from + some windows versions won't be seen */ + status = socket_listen(dgmsock->sock, myaddress, lp_dgram_port(), 0, 0); + if (!NT_STATUS_IS_OK(status)) { + socket_listen(dgmsock->sock, myaddress, 0, 0, 0); + } + + /* setup a temporary mailslot listener for replies */ + dgmslot = dgram_mailslot_temp(dgmsock, NBT_MAILSLOT_GETDC, + ntlogon_handler, &replies); + + + ZERO_STRUCT(logon); + logon.command = NTLOGON_SAM_LOGON; + logon.req.logon.request_count = 0; + logon.req.logon.computer_name = TEST_NAME; + logon.req.logon.user_name = TEST_NAME"$"; + logon.req.logon.mailslot_name = dgmslot->mailslot_name; + logon.req.logon.acct_control = ACB_WSTRUST; + logon.req.logon.sid = *dom_sid_parse_talloc(dgmslot, dom_sid); + logon.req.logon.nt_version = 1; + logon.req.logon.lmnt_token = 0xFFFF; + logon.req.logon.lm20_token = 0xFFFF; + + + myname.name = TEST_NAME; + myname.type = NBT_NAME_CLIENT; + myname.scope = NULL; + + status = dgram_mailslot_ntlogon_send(dgmsock, &name, address, + 0, &myname, &logon); + if (!NT_STATUS_IS_OK(status)) { + printf("Failed to send ntlogon request - %s\n", nt_errstr(status)); + goto failed; + } + + + while (timeval_elapsed(&tv) < 5 && replies == 0) { + event_loop_once(dgmsock->event_ctx); + } + + torture_leave_domain(join_ctx); + talloc_free(dgmsock); + return True; + +failed: + torture_leave_domain(join_ctx); + talloc_free(dgmsock); + return False; +} + + /* test nbt dgram operations */ @@ -127,7 +234,7 @@ BOOL torture_nbt_dgram(void) NTSTATUS status; BOOL ret = True; - name.name = lp_parm_string(-1, "torture", "host"); + name.name = lp_workgroup(); name.type = NBT_NAME_PDC; name.scope = NULL; @@ -141,6 +248,7 @@ BOOL torture_nbt_dgram(void) } ret &= nbt_test_netlogon(mem_ctx, name, address); + ret &= nbt_test_ntlogon(mem_ctx, name, address); talloc_free(mem_ctx); diff --git a/source4/torture/rpc/testjoin.c b/source4/torture/rpc/testjoin.c index 5e4c5a32f3..270d8ff7b7 100644 --- a/source4/torture/rpc/testjoin.c +++ b/source4/torture/rpc/testjoin.c @@ -32,6 +32,7 @@ struct test_join { struct dcerpc_pipe *p; struct policy_handle user_handle; + const char *dom_sid; }; @@ -156,6 +157,8 @@ struct test_join *torture_create_testuser(const char *username, goto failed; } + join->dom_sid = dom_sid_string(join, l.out.sid); + o.in.connect_handle = &handle; o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; o.in.sid = l.out.sid; @@ -309,6 +312,14 @@ void torture_leave_domain(struct test_join *join) talloc_free(join); } +/* + return the dom sid for a test join +*/ +const char *torture_join_sid(struct test_join *join) +{ + return join->dom_sid; +} + struct test_join_ads_dc { struct test_join *join; -- cgit