From 9b65a7c38fd78ff71d5382af9a445d712f5d7a59 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 24 Apr 2008 11:49:41 +0100 Subject: Remove unused KANJI and terminal code options. Someone can re-add this with tests and an actual implementation. Andrew Bartlett (This used to be commit 62136febe7bb1122a57737ca43d1ed0800453d77) --- source4/client/client.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/source4/client/client.c b/source4/client/client.c index 79cc1b5382..120a80ccd2 100644 --- a/source4/client/client.c +++ b/source4/client/client.c @@ -3124,11 +3124,6 @@ static int do_message_op(const char *netbios_name, const char *desthost, const char *query_host = NULL; bool message = false; const char *desthost = NULL; -#ifdef KANJI - const char *term_code = KANJI; -#else - const char *term_code = ""; -#endif /* KANJI */ poptContext pc; const char *service = NULL; int port = 0; @@ -3148,7 +3143,6 @@ static int do_message_op(const char *netbios_name, const char *desthost, { "ip-address", 'I', POPT_ARG_STRING, NULL, 'I', "Use this IP to connect to", "IP" }, { "stderr", 'E', POPT_ARG_NONE, NULL, 'E', "Write messages to stderr instead of stdout" }, { "list", 'L', POPT_ARG_STRING, NULL, 'L', "Get a list of shares available on a host", "HOST" }, - { "terminal", 't', POPT_ARG_STRING, NULL, 't', "Terminal I/O code {sjis|euc|jis7|jis8|junet|hex}", "CODE" }, { "directory", 'D', POPT_ARG_STRING, NULL, 'D', "Start from directory", "DIR" }, { "command", 'c', POPT_ARG_STRING, &cmdstr, 'c', "Execute semicolon separated commands" }, { "send-buffer", 'b', POPT_ARG_INT, NULL, 'b', "Changes the transmit/send buffer", "BYTES" }, @@ -3190,9 +3184,6 @@ static int do_message_op(const char *netbios_name, const char *desthost, case 'L': query_host = strdup(poptGetOptArg(pc)); break; - case 't': - term_code = strdup(poptGetOptArg(pc)); - break; case 'D': base_directory = strdup(poptGetOptArg(pc)); break; -- cgit From ed5ddabc43c484fe6eca3bd4b0cc22eb5aa9a33a Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 24 Apr 2008 13:30:36 +0100 Subject: Add documentation to session token functions. (This used to be commit ec4a108d1d35cd4bb2170f1bb122546266b9b745) --- source4/auth/session.h | 14 ++++++++++++-- source4/auth/system_session.c | 7 ++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/source4/auth/session.h b/source4/auth/session.h index 9b5fba7f39..933b14a1b4 100644 --- a/source4/auth/session.h +++ b/source4/auth/session.h @@ -1,6 +1,6 @@ /* Unix SMB/CIFS implementation. - Auth session handling + Process and provide the logged on user's authorization token Copyright (C) Andrew Bartlett 2001 Copyright (C) Stefan Metzmacher 2005 @@ -30,8 +30,18 @@ struct auth_session_info { #include "librpc/gen_ndr/netlogon.h" -struct auth_session_info *system_session_anon(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx); +/* Create a security token for a session SYSTEM (the most + * trusted/prvilaged account), including the local machine account as + * the off-host credentials */ struct auth_session_info *system_session(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx) ; + +/* + * Create a system session, but with anonymous credentials (so we do + * not need to open secrets.ldb) + */ +struct auth_session_info *system_session_anon(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx); + + NTSTATUS auth_anonymous_server_info(TALLOC_CTX *mem_ctx, const char *netbios_name, struct auth_serversupplied_info **_server_info) ; diff --git a/source4/auth/system_session.c b/source4/auth/system_session.c index e99bbbb1ab..1d227fe468 100644 --- a/source4/auth/system_session.c +++ b/source4/auth/system_session.c @@ -147,9 +147,10 @@ static NTSTATUS generate_session_info(TALLOC_CTX *mem_ctx, -/** - Create a system session, with machine account credentials -*/ +/* Create a security token for a session SYSTEM (the most + * trusted/prvilaged account), including the local machine account as + * the off-host credentials + */ _PUBLIC_ struct auth_session_info *system_session(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx) { NTSTATUS nt_status; -- cgit From d67e47e5cd11c928299dc03ce2ff521e2d3cca83 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 24 Apr 2008 16:27:36 +0100 Subject: Add comment explaining why io.in.workgroup isn't important. This protocol feild isn't used by servers (apparently), so we might be able to get rid of it. Andrew Bartlett (This used to be commit 58935acc7c8e97323d5d5979234ef26ef8a100a4) --- source4/libcli/raw/clitree.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source4/libcli/raw/clitree.c b/source4/libcli/raw/clitree.c index d5075f9271..15cd70833c 100644 --- a/source4/libcli/raw/clitree.c +++ b/source4/libcli/raw/clitree.c @@ -193,6 +193,11 @@ NTSTATUS smbcli_tree_full_connection(TALLOC_CTX *parent_ctx, io.in.service_type = service_type; io.in.credentials = credentials; io.in.fallback_to_anonymous = false; + + /* This workgroup gets sent out by the SPNEGO session setup. + * I don't know of any servers that look at it, so we might + * hardcode it to "" some day, when the war on global_loadparm + * is complete -- abartlet 2008-04-28 */ io.in.workgroup = lp_workgroup(global_loadparm); io.in.options = *options; -- cgit From 0d1fe706e347ddb03f58da5f67853090f6d2ae72 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 25 Apr 2008 09:25:14 +0100 Subject: Remove vampire.py as the 'net' binary is the right interface. As some future point we might get these scripting interfaces into better shape, and provide a python interface to this functionality again. Andrew Bartlett (This used to be commit 717dcb2c54b1e22b7c8efb322deec55abb7689c2) --- source4/setup/vampire.py | 53 ------------------------------------------------ 1 file changed, 53 deletions(-) delete mode 100755 source4/setup/vampire.py diff --git a/source4/setup/vampire.py b/source4/setup/vampire.py deleted file mode 100755 index 728c53146a..0000000000 --- a/source4/setup/vampire.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/python - -# Unix SMB/CIFS implementation. -# Vampire a remote domain -# Copyright (C) Jelmer Vernooij 2007 -# -# 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 3 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, see . -# - -from net import libnet -import optparse -import samba.getopt as options -import param -from auth import system_session -import sys - -parser = optparse.OptionParser("vampire [options] ") -sambaopts = options.SambaOptions(parser) -parser.add_option_group(sambaopts) -parser.add_option_group(options.VersionOptions(parser)) -credopts = options.CredentialsOptions(parser) -parser.add_option_group(credopts) - -opts, args = parser.parse_args() - -if len(args) < 1: - parser.print_usage() - sys.exit(1) - -def vampire(domain, session_info, credentials, lp): - ctx = libnet(lp_ctx=lp) - ctx.cred = credentials - machine_creds = Credentials(); - machine_creds.set_domain(domain); - if not machine_creds.set_machine_account(): - raise Exception("Failed to access domain join information!") - ctx.samsync_ldb(vampire_ctx, machine_creds=machine_creds, - session_info=session_info) - -lp = sambaopts.get_loadparm() -vampire(args[0], session_info=system_session(), - credentials=credopts.get_credentials(), lp=lp) -- cgit From ff1ad0430095b00daa9e66b45cd85b6f65ab9687 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 25 Apr 2008 15:05:07 +0100 Subject: When a test harness program fails, make the testsuite fail. The problem fixed here is that pidl tests were not causing the 'number of tests failing' count to increase, due to the way return codes are processed on pipelines, in the shell. By setting an exit code if we print 'failure', we ensure we fail appropriately. Andrew Bartlett (This used to be commit 687e81883d37e3d1f55d3a7a87e20fb860888dde) --- source4/script/harness2subunit.pl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source4/script/harness2subunit.pl b/source4/script/harness2subunit.pl index c14e4730e0..9f2391ad6c 100755 --- a/source4/script/harness2subunit.pl +++ b/source4/script/harness2subunit.pl @@ -1,7 +1,7 @@ #!/usr/bin/perl my $firstline = 1; - +my $error = 0; while() { if ($firstline) { $firstline = 0; @@ -10,6 +10,7 @@ while() { if (/^not ok (\d+) - (.*)$/) { print "test: $2\n"; print "failure: $2\n"; + $error = 1; } elsif (/^ok (\d+) - (.*)$/) { print "test: $2\n"; print "success: $2\n"; @@ -22,7 +23,10 @@ while() { } elsif (/^not ok (\d+)$/) { print "test: $1\n"; print "failure: $1\n"; + $error = 1; } else { print; } } +exit $error; + -- cgit From ee70e01e3e4d5f4501dea1b217ff29d978b94548 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 25 Apr 2008 15:08:23 +0100 Subject: Don't compile files twice when the compilation fails. Andrew Bartlett (This used to be commit 53ea233649d12d77233611e272cf5f470177571c) --- source4/build/make/rules.mk | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source4/build/make/rules.mk b/source4/build/make/rules.mk index 541fa018db..8c5b1fe6f3 100644 --- a/source4/build/make/rules.mk +++ b/source4/build/make/rules.mk @@ -212,8 +212,7 @@ include/includes.d: include/includes.h @-mkdir -p `dirname $@` @$(COMPILE) && exit 0 ; \ echo "The following command failed:" 1>&2;\ - echo "$(COMPILE)" 1>&2;\ - $(COMPILE) >/dev/null 2>&1 + echo "$(COMPILE)" 1>&2 && exit 1 -- cgit From c4219fd8030494986c5fa418c46defb1a9c05c7e Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 25 Apr 2008 15:08:52 +0100 Subject: Make the composite 'connect to server' code useful for security=server The ability to short-circuit the connection code to only do a negprot allows us to do the rest once we have the user's password. We return the 8 byte challenge so we can pass it to the client. Andrew Bartlett (This used to be commit 40fe386b0374df8b390b995c332d048dbbc08f1b) --- source4/libcli/smb_composite/connect.c | 42 ++++++++++++++++++++-------- source4/libcli/smb_composite/sesssetup.c | 2 +- source4/libcli/smb_composite/smb_composite.h | 5 ++-- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/source4/libcli/smb_composite/connect.c b/source4/libcli/smb_composite/connect.c index c4abfa5e37..4400c61a81 100644 --- a/source4/libcli/smb_composite/connect.c +++ b/source4/libcli/smb_composite/connect.c @@ -38,7 +38,9 @@ enum connect_stage {CONNECT_RESOLVE, CONNECT_NEGPROT, CONNECT_SESSION_SETUP, CONNECT_SESSION_SETUP_ANON, - CONNECT_TCON}; + CONNECT_TCON, + CONNECT_DONE +}; struct connect_state { enum connect_stage stage; @@ -97,8 +99,7 @@ static NTSTATUS connect_tcon(struct composite_context *c, state->io_tcon->tconx.out.fs_type); } - /* all done! */ - c->state = COMPOSITE_STATE_DONE; + state->stage = CONNECT_DONE; return NT_STATUS_OK; } @@ -203,6 +204,13 @@ static NTSTATUS connect_session_setup(struct composite_context *c, state->session->vuid = state->io_setup->out.vuid; + /* If we don't have a remote share name then this indicates that + * we don't want to do a tree connect */ + if (!io->in.service) { + state->stage = CONNECT_DONE; + return NT_STATUS_OK; + } + /* setup for a tconx */ io->out.tree = smbcli_tree_init(state->session, state, true); NT_STATUS_HAVE_NO_MEMORY(io->out.tree); @@ -251,10 +259,23 @@ static NTSTATUS connect_negprot(struct composite_context *c, status = smb_raw_negotiate_recv(state->req); NT_STATUS_NOT_OK_RETURN(status); + if (!(state->transport->negotiate.capabilities & CAP_EXTENDED_SECURITY)) { + io->out.negprot_challenge = state->transport->negotiate.secblob; + } else { + io->out.negprot_challenge = data_blob(NULL, 0); + } + + /* If we don't have any credentials then this indicates that + * we don't want to do a session setup */ + if (!io->in.credentials) { + state->stage = CONNECT_DONE; + return NT_STATUS_OK; + } + /* next step is a session setup */ state->session = smbcli_session_init(state->transport, state, true); NT_STATUS_HAVE_NO_MEMORY(state->session); - + state->io_setup = talloc(c, struct smb_composite_sesssetup); NT_STATUS_HAVE_NO_MEMORY(state->io_setup); @@ -272,6 +293,7 @@ static NTSTATUS connect_negprot(struct composite_context *c, state->creq->async.fn = composite_handler; state->creq->async.private_data = c; + state->stage = CONNECT_SESSION_SETUP; return NT_STATUS_OK; @@ -405,13 +427,11 @@ static void state_handler(struct composite_context *c) break; } - if (!NT_STATUS_IS_OK(c->status)) { - c->state = COMPOSITE_STATE_ERROR; - } - - if (c->state >= COMPOSITE_STATE_DONE && - c->async.fn) { - c->async.fn(c); + if (state->stage == CONNECT_DONE) { + /* all done! */ + composite_done(c); + } else { + composite_is_ok(c); } } diff --git a/source4/libcli/smb_composite/sesssetup.c b/source4/libcli/smb_composite/sesssetup.c index 1427fe525b..11ac37e257 100644 --- a/source4/libcli/smb_composite/sesssetup.c +++ b/source4/libcli/smb_composite/sesssetup.c @@ -224,7 +224,6 @@ static NTSTATUS session_setup_nt1(struct composite_context *c, { NTSTATUS nt_status; struct sesssetup_state *state = talloc_get_type(c->private_data, struct sesssetup_state); - const char *password = cli_credentials_get_password(io->in.credentials); DATA_BLOB names_blob = NTLMv2_generate_names_blob(state, lp_iconv_convenience(global_loadparm), session->transport->socket->hostname, lp_workgroup(global_loadparm)); DATA_BLOB session_key; int flags = CLI_CRED_NTLM_AUTH; @@ -266,6 +265,7 @@ static NTSTATUS session_setup_nt1(struct composite_context *c, data_blob_free(&session_key); } else if (session->options.plaintext_auth) { + const char *password = cli_credentials_get_password(io->in.credentials); state->setup.nt1.in.password1 = data_blob_talloc(state, password, strlen(password)); state->setup.nt1.in.password2 = data_blob(NULL, 0); } else { diff --git a/source4/libcli/smb_composite/smb_composite.h b/source4/libcli/smb_composite/smb_composite.h index e7e131869c..80746f2732 100644 --- a/source4/libcli/smb_composite/smb_composite.h +++ b/source4/libcli/smb_composite/smb_composite.h @@ -83,8 +83,8 @@ struct smb_composite_savefile { - socket establishment - session request - negprot - - session setup - - tree connect + - session setup (if credentials are not NULL) + - tree connect (if service is not NULL) */ struct smb_composite_connect { struct { @@ -101,6 +101,7 @@ struct smb_composite_connect { struct { struct smbcli_tree *tree; bool anonymous_fallback_done; + DATA_BLOB negprot_challenge; } out; }; -- cgit From 35e45534c64930a0f22c5975c64be41d96265a00 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 25 Apr 2008 15:59:22 +0100 Subject: Revert to using the old CIFS connection API. Rather than add a new 'out' member to the API, simply fill in the 'tree' early enough that we can access the server challenge there. Andrew Bartlett (This used to be commit 6dbbcf8aaf9b93af970d1701dfb185460d4dc788) --- source4/libcli/smb_composite/connect.c | 24 ++++++++---------------- source4/libcli/smb_composite/smb_composite.h | 1 - 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/source4/libcli/smb_composite/connect.c b/source4/libcli/smb_composite/connect.c index 4400c61a81..39c614f042 100644 --- a/source4/libcli/smb_composite/connect.c +++ b/source4/libcli/smb_composite/connect.c @@ -122,9 +122,6 @@ static NTSTATUS connect_session_setup_anon(struct composite_context *c, state->session->vuid = state->io_setup->out.vuid; /* setup for a tconx */ - io->out.tree = smbcli_tree_init(state->session, state, true); - NT_STATUS_HAVE_NO_MEMORY(io->out.tree); - state->io_tcon = talloc(c, union smb_tcon); NT_STATUS_HAVE_NO_MEMORY(state->io_tcon); @@ -211,10 +208,6 @@ static NTSTATUS connect_session_setup(struct composite_context *c, return NT_STATUS_OK; } - /* setup for a tconx */ - io->out.tree = smbcli_tree_init(state->session, state, true); - NT_STATUS_HAVE_NO_MEMORY(io->out.tree); - state->io_tcon = talloc(c, union smb_tcon); NT_STATUS_HAVE_NO_MEMORY(state->io_tcon); @@ -259,11 +252,14 @@ static NTSTATUS connect_negprot(struct composite_context *c, status = smb_raw_negotiate_recv(state->req); NT_STATUS_NOT_OK_RETURN(status); - if (!(state->transport->negotiate.capabilities & CAP_EXTENDED_SECURITY)) { - io->out.negprot_challenge = state->transport->negotiate.secblob; - } else { - io->out.negprot_challenge = data_blob(NULL, 0); - } + /* next step is a session setup */ + state->session = smbcli_session_init(state->transport, state, true); + NT_STATUS_HAVE_NO_MEMORY(state->session); + + /* setup for a tconx (or at least have the structure ready to + * return, if we won't go that far) */ + io->out.tree = smbcli_tree_init(state->session, state, true); + NT_STATUS_HAVE_NO_MEMORY(io->out.tree); /* If we don't have any credentials then this indicates that * we don't want to do a session setup */ @@ -272,10 +268,6 @@ static NTSTATUS connect_negprot(struct composite_context *c, return NT_STATUS_OK; } - /* next step is a session setup */ - state->session = smbcli_session_init(state->transport, state, true); - NT_STATUS_HAVE_NO_MEMORY(state->session); - state->io_setup = talloc(c, struct smb_composite_sesssetup); NT_STATUS_HAVE_NO_MEMORY(state->io_setup); diff --git a/source4/libcli/smb_composite/smb_composite.h b/source4/libcli/smb_composite/smb_composite.h index 80746f2732..afee11ce3b 100644 --- a/source4/libcli/smb_composite/smb_composite.h +++ b/source4/libcli/smb_composite/smb_composite.h @@ -101,7 +101,6 @@ struct smb_composite_connect { struct { struct smbcli_tree *tree; bool anonymous_fallback_done; - DATA_BLOB negprot_challenge; } out; }; -- cgit From 7c5704499a9881493f8bdfcefb095b50ab072a02 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Sat, 26 Apr 2008 09:50:15 +0100 Subject: Fix dependencies on gensec_krb5 and the NTLMSSP code. This is so that gensec_krb5 does not depend on the NTLM authentication code. Andrew Bartlett (This used to be commit 71ec5bfb3e973bd68649a598d006efcdda18f1b6) --- source4/auth/gensec/config.mk | 2 +- source4/auth/ntlmssp/config.mk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source4/auth/gensec/config.mk b/source4/auth/gensec/config.mk index cfb3493484..8b602e75f0 100644 --- a/source4/auth/gensec/config.mk +++ b/source4/auth/gensec/config.mk @@ -20,7 +20,7 @@ PUBLIC_HEADERS += auth/gensec/gensec.h [MODULE::gensec_krb5] SUBSYSTEM = gensec INIT_FUNCTION = gensec_krb5_init -PRIVATE_DEPENDENCIES = CREDENTIALS KERBEROS auth auth_sam +PRIVATE_DEPENDENCIES = CREDENTIALS KERBEROS auth_session auth_sam # End MODULE gensec_krb5 ################################################ diff --git a/source4/auth/ntlmssp/config.mk b/source4/auth/ntlmssp/config.mk index f8e711feda..849448f5bb 100644 --- a/source4/auth/ntlmssp/config.mk +++ b/source4/auth/ntlmssp/config.mk @@ -9,7 +9,7 @@ MSRPC_PARSE_OBJ_FILES = $(addprefix auth/ntlmssp/, ntlmssp_parse.o) SUBSYSTEM = gensec INIT_FUNCTION = gensec_ntlmssp_init PRIVATE_PROTO_HEADER = proto.h -PRIVATE_DEPENDENCIES = MSRPC_PARSE CREDENTIALS +PRIVATE_DEPENDENCIES = MSRPC_PARSE CREDENTIALS auth OUTPUT_TYPE = MERGED_OBJ # End MODULE gensec_ntlmssp ################################################ -- cgit From 1e973565b6c0cb738b25a2d9439d5acb441701f4 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 27 Apr 2008 14:02:46 +0100 Subject: Move subunit infrastructure code into lib/torture. (This used to be commit 5b44d8121de7735d69e6238a1442aff034a8ebd3) --- source4/lib/basic.mk | 1 + source4/lib/crypto/sha1test.c | 2 +- source4/lib/torture/config.mk | 11 + source4/lib/torture/torture.c | 579 ++++++++++++++++++++++++++++++++++ source4/lib/torture/torture.h | 396 ++++++++++++++++++++++++ source4/lib/util/tests/str.c | 2 +- source4/torture/basic/base.c | 2 +- source4/torture/basic/locking.c | 3 +- source4/torture/basic/misc.c | 2 +- source4/torture/config.mk | 17 +- source4/torture/ldap/common.c | 2 +- source4/torture/libnet/libnet.c | 2 +- source4/torture/local/dbspeed.c | 2 +- source4/torture/local/local.c | 2 +- source4/torture/nbench/nbench.c | 3 +- source4/torture/nbt/nbt.c | 2 +- source4/torture/ndr/ndr.c | 2 +- source4/torture/rap/rap.c | 2 +- source4/torture/raw/lookuprate.c | 2 +- source4/torture/raw/raw.c | 4 +- source4/torture/rpc/rpc.c | 2 +- source4/torture/rpc/rpc.h | 2 +- source4/torture/rpc/spoolss_notify.c | 1 - source4/torture/rpc/spoolss_win.c | 1 - source4/torture/smb2/smb2.c | 2 +- source4/torture/smbtorture.c | 2 +- source4/torture/smbtorture.h | 40 +++ source4/torture/torture.h | 41 --- source4/torture/ui.c | 580 ----------------------------------- source4/torture/ui.h | 396 ------------------------ source4/torture/unix/unix.c | 2 +- source4/torture/util.h | 5 + source4/torture/util_smb.c | 1 - source4/torture/winbind/winbind.c | 2 +- 34 files changed, 1056 insertions(+), 1059 deletions(-) create mode 100644 source4/lib/torture/config.mk create mode 100644 source4/lib/torture/torture.c create mode 100644 source4/lib/torture/torture.h create mode 100644 source4/torture/smbtorture.h delete mode 100644 source4/torture/torture.h delete mode 100644 source4/torture/ui.c delete mode 100644 source4/torture/ui.h diff --git a/source4/lib/basic.mk b/source4/lib/basic.mk index 71acb94492..e7e0ba80c4 100644 --- a/source4/lib/basic.mk +++ b/source4/lib/basic.mk @@ -16,6 +16,7 @@ mkinclude util/config.mk mkinclude tdr/config.mk mkinclude dbwrap/config.mk mkinclude crypto/config.mk +mkinclude torture/config.mk [SUBSYSTEM::LIBCOMPRESSION] diff --git a/source4/lib/crypto/sha1test.c b/source4/lib/crypto/sha1test.c index 0e943bd74d..7777764277 100644 --- a/source4/lib/crypto/sha1test.c +++ b/source4/lib/crypto/sha1test.c @@ -17,7 +17,7 @@ */ #include "includes.h" -#include "torture/ui.h" +#include "torture/torture.h" #include "lib/crypto/crypto.h" diff --git a/source4/lib/torture/config.mk b/source4/lib/torture/config.mk new file mode 100644 index 0000000000..e981ee0c99 --- /dev/null +++ b/source4/lib/torture/config.mk @@ -0,0 +1,11 @@ +# TORTURE subsystem +[LIBRARY::torture] +PUBLIC_DEPENDENCIES = \ + LIBSAMBA-HOSTCONFIG \ + LIBSAMBA-UTIL \ + LIBTALLOC + +PC_FILES += lib/torture/torture.pc +torture_OBJ_FILES = $(addprefix lib/torture/, torture.o) + +PUBLIC_HEADERS += lib/torture/torture.h diff --git a/source4/lib/torture/torture.c b/source4/lib/torture/torture.c new file mode 100644 index 0000000000..3f2c7848aa --- /dev/null +++ b/source4/lib/torture/torture.c @@ -0,0 +1,579 @@ +/* + Unix SMB/CIFS implementation. + SMB torture UI functions + + Copyright (C) Jelmer Vernooij 2006 + + 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 3 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, see . +*/ + +#include "includes.h" +#include "torture/torture.h" +#include "lib/util/dlinklist.h" +#include "param/param.h" +#include "system/filesys.h" +#include "auth/credentials/credentials.h" +#include "lib/cmdline/popt_common.h" + +struct torture_context *torture_context_init(struct event_context *event_ctx, + const struct torture_ui_ops *ui_ops) +{ + struct torture_context *torture = talloc_zero(event_ctx, + struct torture_context); + torture->ui_ops = ui_ops; + torture->returncode = true; + torture->ev = event_ctx; + + if (ui_ops->init) + ui_ops->init(torture); + + return torture; +} + +/** + create a temporary directory. +*/ +_PUBLIC_ NTSTATUS torture_temp_dir(struct torture_context *tctx, + const char *prefix, + char **tempdir) +{ + SMB_ASSERT(tctx->outputdir != NULL); + + *tempdir = talloc_asprintf(tctx, "%s/%s.XXXXXX", tctx->outputdir, + prefix); + NT_STATUS_HAVE_NO_MEMORY(*tempdir); + + if (mkdtemp(*tempdir) == NULL) { + return map_nt_error_from_unix(errno); + } + + return NT_STATUS_OK; +} + +void torture_comment(struct torture_context *context, const char *comment, ...) +{ + va_list ap; + char *tmp; + + if (!context->ui_ops->comment) + return; + + va_start(ap, comment); + tmp = talloc_vasprintf(context, comment, ap); + + context->ui_ops->comment(context, tmp); + + talloc_free(tmp); +} + +void torture_warning(struct torture_context *context, const char *comment, ...) +{ + va_list ap; + char *tmp; + + if (!context->ui_ops->warning) + return; + + va_start(ap, comment); + tmp = talloc_vasprintf(context, comment, ap); + + context->ui_ops->warning(context, tmp); + + talloc_free(tmp); +} + +void torture_result(struct torture_context *context, + enum torture_result result, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + + if (context->last_reason) { + torture_warning(context, "%s", context->last_reason); + talloc_free(context->last_reason); + } + + context->last_result = result; + context->last_reason = talloc_vasprintf(context, fmt, ap); + va_end(ap); +} + +struct torture_suite *torture_suite_create(TALLOC_CTX *ctx, const char *name) +{ + struct torture_suite *suite = talloc_zero(ctx, struct torture_suite); + + suite->name = talloc_strdup(suite, name); + suite->testcases = NULL; + suite->children = NULL; + + return suite; +} + +void torture_tcase_set_fixture(struct torture_tcase *tcase, + bool (*setup) (struct torture_context *, void **), + bool (*teardown) (struct torture_context *, void *)) +{ + tcase->setup = setup; + tcase->teardown = teardown; +} + +static bool wrap_test_with_testcase_const(struct torture_context *torture_ctx, + struct torture_tcase *tcase, + struct torture_test *test) +{ + bool (*fn) (struct torture_context *, + const void *tcase_data, + const void *test_data); + + fn = test->fn; + + return fn(torture_ctx, tcase->data, test->data); +} + +struct torture_test *torture_tcase_add_test_const(struct torture_tcase *tcase, + const char *name, + bool (*run) (struct torture_context *, const void *tcase_data, + const void *test_data), + const void *data) +{ + struct torture_test *test = talloc(tcase, struct torture_test); + + test->name = talloc_strdup(test, name); + test->description = NULL; + test->run = wrap_test_with_testcase_const; + test->fn = run; + test->dangerous = false; + test->data = data; + + DLIST_ADD_END(tcase->tests, test, struct torture_test *); + + return test; +} + + +bool torture_suite_init_tcase(struct torture_suite *suite, + struct torture_tcase *tcase, + const char *name) +{ + tcase->name = talloc_strdup(tcase, name); + tcase->description = NULL; + tcase->setup = NULL; + tcase->teardown = NULL; + tcase->fixture_persistent = true; + tcase->tests = NULL; + + DLIST_ADD_END(suite->testcases, tcase, struct torture_tcase *); + + return true; +} + + +struct torture_tcase *torture_suite_add_tcase(struct torture_suite *suite, + const char *name) +{ + struct torture_tcase *tcase = talloc(suite, struct torture_tcase); + + if (!torture_suite_init_tcase(suite, tcase, name)) + return NULL; + + return tcase; +} + +bool torture_run_suite(struct torture_context *context, + struct torture_suite *suite) +{ + bool ret = true; + struct torture_tcase *tcase; + struct torture_suite *tsuite; + char *old_testname; + + context->level++; + if (context->ui_ops->suite_start) + context->ui_ops->suite_start(context, suite); + + old_testname = context->active_testname; + if (old_testname != NULL) + context->active_testname = talloc_asprintf(context, "%s-%s", + old_testname, suite->name); + else + context->active_testname = talloc_strdup(context, suite->name); + + for (tcase = suite->testcases; tcase; tcase = tcase->next) { + ret &= torture_run_tcase(context, tcase); + } + + for (tsuite = suite->children; tsuite; tsuite = tsuite->next) { + ret &= torture_run_suite(context, tsuite); + } + + talloc_free(context->active_testname); + context->active_testname = old_testname; + + if (context->ui_ops->suite_finish) + context->ui_ops->suite_finish(context, suite); + + context->level--; + + return ret; +} + +void torture_ui_test_start(struct torture_context *context, + struct torture_tcase *tcase, + struct torture_test *test) +{ + if (context->ui_ops->test_start) + context->ui_ops->test_start(context, tcase, test); +} + +int str_list_match(const char *name, char **list) +{ + int i, ret = 0; + if (list == NULL) + return 0; + + for (i = 0; list[i]; i++) { + if (gen_fnmatch(list[i], name) == 0) + ret++; + } + return ret; +} + +void torture_ui_test_result(struct torture_context *context, + enum torture_result result, + const char *comment) +{ + if (context->ui_ops->test_result) + context->ui_ops->test_result(context, result, comment); + + if (result == TORTURE_ERROR || result == TORTURE_FAIL) + context->returncode = false; +} + +static bool internal_torture_run_test(struct torture_context *context, + struct torture_tcase *tcase, + struct torture_test *test, + bool already_setup) +{ + bool success; + char *old_testname; + + if (tcase == NULL || strcmp(test->name, tcase->name) != 0) { + old_testname = context->active_testname; + context->active_testname = talloc_asprintf(context, "%s-%s", old_testname, test->name); + } + + context->active_tcase = tcase; + context->active_test = test; + + torture_ui_test_start(context, tcase, test); + + context->last_reason = NULL; + context->last_result = TORTURE_OK; + + if (!already_setup && tcase->setup && + !tcase->setup(context, &(tcase->data))) { + if (context->last_reason == NULL) + context->last_reason = talloc_strdup(context, "Setup failure"); + context->last_result = TORTURE_ERROR; + success = false; + } else if (test->dangerous && + !torture_setting_bool(context, "dangerous", false)) { + context->last_result = TORTURE_SKIP; + context->last_reason = talloc_asprintf(context, + "disabled %s - enable dangerous tests to use", test->name); + success = true; + } else { + success = test->run(context, tcase, test); + + if (!success && context->last_result == TORTURE_OK) { + if (context->last_reason == NULL) + context->last_reason = talloc_strdup(context, "Unknown error/failure"); + context->last_result = TORTURE_ERROR; + } + } + + if (!already_setup && tcase->teardown && !tcase->teardown(context, tcase->data)) { + if (context->last_reason == NULL) + context->last_reason = talloc_strdup(context, "Setup failure"); + context->last_result = TORTURE_ERROR; + success = false; + } + + torture_ui_test_result(context, context->last_result, + context->last_reason); + + talloc_free(context->last_reason); + + if (tcase == NULL || strcmp(test->name, tcase->name) != 0) { + talloc_free(context->active_testname); + context->active_testname = old_testname; + } + context->active_test = NULL; + context->active_tcase = NULL; + + return success; +} + +bool torture_run_tcase(struct torture_context *context, + struct torture_tcase *tcase) +{ + bool ret = true; + char *old_testname; + struct torture_test *test; + + context->level++; + + context->active_tcase = tcase; + if (context->ui_ops->tcase_start) + context->ui_ops->tcase_start(context, tcase); + + if (tcase->fixture_persistent && tcase->setup + && !tcase->setup(context, &tcase->data)) { + /* FIXME: Use torture ui ops for reporting this error */ + fprintf(stderr, "Setup failed: "); + if (context->last_reason != NULL) + fprintf(stderr, "%s", context->last_reason); + fprintf(stderr, "\n"); + ret = false; + goto done; + } + + old_testname = context->active_testname; + context->active_testname = talloc_asprintf(context, "%s-%s", + old_testname, tcase->name); + for (test = tcase->tests; test; test = test->next) { + ret &= internal_torture_run_test(context, tcase, test, + tcase->fixture_persistent); + } + talloc_free(context->active_testname); + context->active_testname = old_testname; + + if (tcase->fixture_persistent && tcase->teardown && + !tcase->teardown(context, tcase->data)) + ret = false; + +done: + context->active_tcase = NULL; + + if (context->ui_ops->tcase_finish) + context->ui_ops->tcase_finish(context, tcase); + + context->level--; + + return ret; +} + +bool torture_run_test(struct torture_context *context, + struct torture_tcase *tcase, + struct torture_test *test) +{ + return internal_torture_run_test(context, tcase, test, false); +} + +int torture_setting_int(struct torture_context *test, const char *name, + int default_value) +{ + return lp_parm_int(test->lp_ctx, NULL, "torture", name, default_value); +} + +double torture_setting_double(struct torture_context *test, const char *name, + double default_value) +{ + return lp_parm_double(test->lp_ctx, NULL, "torture", name, default_value); +} + +bool torture_setting_bool(struct torture_context *test, const char *name, + bool default_value) +{ + return lp_parm_bool(test->lp_ctx, NULL, "torture", name, default_value); +} + +const char *torture_setting_string(struct torture_context *test, + const char *name, + const char *default_value) +{ + const char *ret; + + SMB_ASSERT(test != NULL); + SMB_ASSERT(test->lp_ctx != NULL); + + ret = lp_parm_string(test->lp_ctx, NULL, "torture", name); + + if (ret == NULL) + return default_value; + + return ret; +} + +static bool wrap_test_with_simple_tcase_const ( + struct torture_context *torture_ctx, + struct torture_tcase *tcase, + struct torture_test *test) +{ + bool (*fn) (struct torture_context *, const void *tcase_data); + + fn = test->fn; + + return fn(torture_ctx, test->data); +} + +struct torture_tcase *torture_suite_add_simple_tcase_const( + struct torture_suite *suite, const char *name, + bool (*run) (struct torture_context *test, const void *), + const void *data) +{ + struct torture_tcase *tcase; + struct torture_test *test; + + tcase = torture_suite_add_tcase(suite, name); + + test = talloc(tcase, struct torture_test); + + test->name = talloc_strdup(test, name); + test->description = NULL; + test->run = wrap_test_with_simple_tcase_const; + test->fn = run; + test->data = data; + test->dangerous = false; + + DLIST_ADD_END(tcase->tests, test, struct torture_test *); + + return tcase; +} + +static bool wrap_simple_test(struct torture_context *torture_ctx, + struct torture_tcase *tcase, + struct torture_test *test) +{ + bool (*fn) (struct torture_context *); + + fn = test->fn; + + return fn(torture_ctx); +} + +struct torture_tcase *torture_suite_add_simple_test( + struct torture_suite *suite, + const char *name, + bool (*run) (struct torture_context *test)) +{ + struct torture_test *test; + struct torture_tcase *tcase; + + tcase = torture_suite_add_tcase(suite, name); + + test = talloc(tcase, struct torture_test); + + test->name = talloc_strdup(test, name); + test->description = NULL; + test->run = wrap_simple_test; + test->fn = run; + test->dangerous = false; + + DLIST_ADD_END(tcase->tests, test, struct torture_test *); + + return tcase; +} + +bool torture_suite_add_suite(struct torture_suite *suite, + struct torture_suite *child) +{ + if (child == NULL) + return false; + + DLIST_ADD_END(suite->children, child, struct torture_suite *); + + /* FIXME: Check for duplicates and return false if the + * added suite already exists as a child */ + + return true; +} + + +struct torture_suite *torture_find_suite(struct torture_suite *parent, + const char *name) +{ + struct torture_suite *child; + + for (child = parent->children; child; child = child->next) + if (!strcmp(child->name, name)) + return child; + + return NULL; +} + +static bool wrap_test_with_simple_test_const(struct torture_context *torture_ctx, + struct torture_tcase *tcase, + struct torture_test *test) +{ + bool (*fn) (struct torture_context *, const void *tcase_data); + + fn = test->fn; + + return fn(torture_ctx, tcase->data); +} + +struct torture_test *torture_tcase_add_simple_test_const( + struct torture_tcase *tcase, + const char *name, + bool (*run) (struct torture_context *test, + const void *tcase_data)) +{ + struct torture_test *test; + + test = talloc(tcase, struct torture_test); + + test->name = talloc_strdup(test, name); + test->description = NULL; + test->run = wrap_test_with_simple_test_const; + test->fn = run; + test->data = NULL; + test->dangerous = false; + + DLIST_ADD_END(tcase->tests, test, struct torture_test *); + + return test; +} + +static bool wrap_test_with_simple_test(struct torture_context *torture_ctx, + struct torture_tcase *tcase, + struct torture_test *test) +{ + bool (*fn) (struct torture_context *, void *tcase_data); + + fn = test->fn; + + return fn(torture_ctx, tcase->data); +} + +struct torture_test *torture_tcase_add_simple_test(struct torture_tcase *tcase, + const char *name, + bool (*run) (struct torture_context *test, void *tcase_data)) +{ + struct torture_test *test; + + test = talloc(tcase, struct torture_test); + + test->name = talloc_strdup(test, name); + test->description = NULL; + test->run = wrap_test_with_simple_test; + test->fn = run; + test->data = NULL; + test->dangerous = false; + + DLIST_ADD_END(tcase->tests, test, struct torture_test *); + + return test; +} diff --git a/source4/lib/torture/torture.h b/source4/lib/torture/torture.h new file mode 100644 index 0000000000..15b04c2397 --- /dev/null +++ b/source4/lib/torture/torture.h @@ -0,0 +1,396 @@ +/* + Unix SMB/CIFS implementation. + SMB torture UI functions + + Copyright (C) Jelmer Vernooij 2006 + + 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 3 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, see . +*/ + +#ifndef __TORTURE_UI_H__ +#define __TORTURE_UI_H__ + +struct torture_test; +struct torture_context; +struct torture_suite; +struct torture_tcase; + +enum torture_result { + TORTURE_OK=0, + TORTURE_FAIL=1, + TORTURE_ERROR=2, + TORTURE_SKIP=3 +}; + +/* + * These callbacks should be implemented by any backend that wishes + * to listen to reports from the torture tests. + */ +struct torture_ui_ops +{ + void (*init) (struct torture_context *); + void (*comment) (struct torture_context *, const char *); + void (*warning) (struct torture_context *, const char *); + void (*suite_start) (struct torture_context *, struct torture_suite *); + void (*suite_finish) (struct torture_context *, struct torture_suite *); + void (*tcase_start) (struct torture_context *, struct torture_tcase *); + void (*tcase_finish) (struct torture_context *, struct torture_tcase *); + void (*test_start) (struct torture_context *, + struct torture_tcase *, + struct torture_test *); + void (*test_result) (struct torture_context *, + enum torture_result, const char *reason); +}; + +void torture_ui_test_start(struct torture_context *context, + struct torture_tcase *tcase, + struct torture_test *test); + +void torture_ui_test_result(struct torture_context *context, + enum torture_result result, + const char *comment); + +/* + * Holds information about a specific run of the testsuite. + * The data in this structure should be considered private to + * the torture tests and should only be used directly by the torture + * code and the ui backends. + * + * Torture tests should instead call the torture_*() macros and functions + * specified below. + */ + +struct torture_context +{ + const struct torture_ui_ops *ui_ops; + void *ui_data; + + char *active_testname; + struct torture_test *active_test; + struct torture_tcase *active_tcase; + + bool quiet; /* Whether tests should avoid writing output to stdout */ + + enum torture_result last_result; + char *last_reason; + + bool returncode; + + const char *outputdir; + int level; + struct event_context *ev; + + struct loadparm_context *lp_ctx; +}; + +/* + * Describes a particular torture test + */ +struct torture_test { + const char *name; + const char *description; + bool dangerous; + /* Function to call to run this test */ + bool (*run) (struct torture_context *torture_ctx, + struct torture_tcase *tcase, + struct torture_test *test); + + struct torture_test *prev, *next; + + /* Pointer to the actual test function. This is run by the + * run() function above. */ + void *fn; + const void *data; +}; + +/* + * Describes a particular test case. + */ +struct torture_tcase { + const char *name; + const char *description; + bool (*setup) (struct torture_context *tcase, void **data); + bool (*teardown) (struct torture_context *tcase, void *data); + bool fixture_persistent; + void *data; + struct torture_test *tests; + struct torture_tcase *prev, *next; +}; + +struct torture_suite +{ + const char *name; + const char *description; + struct torture_tcase *testcases; + struct torture_suite *children; + + /* Pointers to siblings of this torture suite */ + struct torture_suite *prev, *next; +}; + +/** Create a new torture suite */ +struct torture_suite *torture_suite_create(TALLOC_CTX *mem_ctx, + const char *name); + +/** Change the setup and teardown functions for a testcase */ +void torture_tcase_set_fixture(struct torture_tcase *tcase, + bool (*setup) (struct torture_context *, void **), + bool (*teardown) (struct torture_context *, void *)); + +/* Add another test to run for a particular testcase */ +struct torture_test *torture_tcase_add_test_const(struct torture_tcase *tcase, + const char *name, + bool (*run) (struct torture_context *test, + const void *tcase_data, const void *test_data), + const void *test_data); + +/* Add a testcase to a testsuite */ +struct torture_tcase *torture_suite_add_tcase(struct torture_suite *suite, + const char *name); + +/* Convenience wrapper that adds a testcase against only one + * test will be run */ +struct torture_tcase *torture_suite_add_simple_tcase_const( + struct torture_suite *suite, + const char *name, + bool (*run) (struct torture_context *test, + const void *test_data), + const void *data); + +/* Convenience function that adds a test which only + * gets the test case data */ +struct torture_test *torture_tcase_add_simple_test_const( + struct torture_tcase *tcase, + const char *name, + bool (*run) (struct torture_context *test, + const void *tcase_data)); + +/* Convenience wrapper that adds a test that doesn't need any + * testcase data */ +struct torture_tcase *torture_suite_add_simple_test( + struct torture_suite *suite, + const char *name, + bool (*run) (struct torture_context *test)); + +/* Add a child testsuite to an existing testsuite */ +bool torture_suite_add_suite(struct torture_suite *suite, + struct torture_suite *child); + +/* Run the specified testsuite recursively */ +bool torture_run_suite(struct torture_context *context, + struct torture_suite *suite); + +/* Run the specified testcase */ +bool torture_run_tcase(struct torture_context *context, + struct torture_tcase *tcase); + +/* Run the specified test */ +bool torture_run_test(struct torture_context *context, + struct torture_tcase *tcase, + struct torture_test *test); + +void torture_comment(struct torture_context *test, const char *comment, ...) PRINTF_ATTRIBUTE(2,3); +void torture_warning(struct torture_context *test, const char *comment, ...) PRINTF_ATTRIBUTE(2,3); +void torture_result(struct torture_context *test, + enum torture_result, const char *reason, ...) PRINTF_ATTRIBUTE(3,4); + +#define torture_assert(torture_ctx,expr,cmt) \ + if (!(expr)) { \ + torture_result(torture_ctx, TORTURE_FAIL, __location__": Expression `%s' failed: %s", __STRING(expr), cmt); \ + return false; \ + } + +#define torture_assert_werr_equal(torture_ctx, got, expected, cmt) \ + do { WERROR __got = got, __expected = expected; \ + if (!W_ERROR_EQUAL(__got, __expected)) { \ + torture_result(torture_ctx, TORTURE_FAIL, __location__": "#got" was %s, expected %s: %s", win_errstr(__got), win_errstr(__expected), cmt); \ + return false; \ + } \ + } while (0) + +#define torture_assert_ntstatus_equal(torture_ctx,got,expected,cmt) \ + do { NTSTATUS __got = got, __expected = expected; \ + if (!NT_STATUS_EQUAL(__got, __expected)) { \ + torture_result(torture_ctx, TORTURE_FAIL, __location__": "#got" was %s, expected %s: %s", nt_errstr(__got), nt_errstr(__expected), cmt); \ + return false; \ + }\ + } while(0) + +#define torture_assert_ndr_err_equal(torture_ctx,got,expected,cmt) \ + do { enum ndr_err_code __got = got, __expected = expected; \ + if (__got != __expected) { \ + torture_result(torture_ctx, TORTURE_FAIL, __location__": "#got" was %d, expected %d (%s): %s", __got, __expected, __STRING(expected), cmt); \ + return false; \ + }\ + } while(0) + +#define torture_assert_casestr_equal(torture_ctx,got,expected,cmt) \ + do { const char *__got = (got), *__expected = (expected); \ + if (!strequal(__got, __expected)) { \ + torture_result(torture_ctx, TORTURE_FAIL, __location__": "#got" was %s, expected %s: %s", __got, __expected, cmt); \ + return false; \ + } \ + } while(0) + +#define torture_assert_str_equal(torture_ctx,got,expected,cmt)\ + do { const char *__got = (got), *__expected = (expected); \ + if (strcmp_safe(__got, __expected) != 0) { \ + torture_result(torture_ctx, TORTURE_FAIL, \ + __location__": "#got" was %s, expected %s: %s", \ + __got, __expected, cmt); \ + return false; \ + } \ + } while(0) + +#define torture_assert_mem_equal(torture_ctx,got,expected,len,cmt)\ + do { const void *__got = (got), *__expected = (expected); \ + if (memcmp(__got, __expected, len) != 0) { \ + torture_result(torture_ctx, TORTURE_FAIL, \ + __location__": "#got" of len %d did not match"#expected": %s", len, cmt); \ + return false; \ + } \ + } while(0) + +#define torture_assert_file_contains_text(torture_ctx,filename,expected,cmt)\ + do { \ + char *__got; \ + const char *__expected = (expected); \ + size_t __size; \ + __got = file_load(filename, &__size, torture_ctx); \ + if (__got == NULL) { \ + torture_result(torture_ctx, TORTURE_FAIL, \ + __location__": unable to open %s: %s\n", \ + filename, cmt); \ + return false; \ + } \ + \ + if (strcmp_safe(__got, __expected) != 0) { \ + torture_result(torture_ctx, TORTURE_FAIL, \ + __location__": %s contained:\n%sExpected: %s%s\n", \ + filename, __got, __expected, cmt); \ + talloc_free(__got); \ + return false; \ + } \ + talloc_free(__got); \ + } while(0) + +#define torture_assert_file_contains(torture_ctx,filename,expected,cmt)\ + do { const char *__got, *__expected = (expected); \ + size_t __size; \ + __got = file_load(filename, *size, torture_ctx); \ + if (strcmp_safe(__got, __expected) != 0) { \ + torture_result(torture_ctx, TORTURE_FAIL, \ + __location__": %s contained:\n%sExpected: %s%s\n", \ + __got, __expected, cmt); \ + talloc_free(__got); \ + return false; \ + } \ + talloc_free(__got); \ + } while(0) + +#define torture_assert_int_equal(torture_ctx,got,expected,cmt)\ + do { int __got = (got), __expected = (expected); \ + if (__got != __expected) { \ + torture_result(torture_ctx, TORTURE_FAIL, \ + __location__": "#got" was %d, expected %d: %s", \ + __got, __expected, cmt); \ + return false; \ + } \ + } while(0) + +#define torture_assert_u64_equal(torture_ctx,got,expected,cmt)\ + do { uint64_t __got = (got), __expected = (expected); \ + if (__got != __expected) { \ + torture_result(torture_ctx, TORTURE_FAIL, \ + __location__": "#got" was %llu, expected %llu: %s", \ + (unsigned long long)__got, (unsigned long long)__expected, cmt); \ + return false; \ + } \ + } while(0) + +#define torture_assert_errno_equal(torture_ctx,expected,cmt)\ + do { int __expected = (expected); \ + if (errno != __expected) { \ + torture_result(torture_ctx, TORTURE_FAIL, \ + __location__": errno was %d (%s), expected %d: %s: %s", \ + errno, strerror(errno), __expected, \ + strerror(__expected), cmt); \ + return false; \ + } \ + } while(0) + + + +#define torture_skip(torture_ctx,cmt) do {\ + torture_result(torture_ctx, TORTURE_SKIP, __location__": %s", cmt);\ + return true; \ + } while(0) +#define torture_fail(torture_ctx,cmt) do {\ + torture_result(torture_ctx, TORTURE_FAIL, __location__": %s", cmt);\ + return false; \ + } while (0) +#define torture_fail_goto(torture_ctx,label,cmt) do {\ + torture_result(torture_ctx, TORTURE_FAIL, __location__": %s", cmt);\ + goto label; \ + } while (0) + +#define torture_out stderr + +/* Convenience macros */ +#define torture_assert_ntstatus_ok(torture_ctx,expr,cmt) \ + torture_assert_ntstatus_equal(torture_ctx,expr,NT_STATUS_OK,cmt) + +#define torture_assert_werr_ok(torture_ctx,expr,cmt) \ + torture_assert_werr_equal(torture_ctx,expr,WERR_OK,cmt) + +#define torture_assert_ndr_success(torture_ctx,expr,cmt) \ + torture_assert_ndr_err_equal(torture_ctx,expr,NDR_ERR_SUCCESS,cmt) + +/* Getting settings */ +const char *torture_setting_string(struct torture_context *test, \ + const char *name, + const char *default_value); + +int torture_setting_int(struct torture_context *test, + const char *name, + int default_value); + +double torture_setting_double(struct torture_context *test, + const char *name, + double default_value); + +bool torture_setting_bool(struct torture_context *test, + const char *name, + bool default_value); + +struct torture_suite *torture_find_suite(struct torture_suite *parent, + const char *name); + +NTSTATUS torture_temp_dir(struct torture_context *tctx, + const char *prefix, + char **tempdir); + +struct torture_test *torture_tcase_add_simple_test(struct torture_tcase *tcase, + const char *name, + bool (*run) (struct torture_context *test, void *tcase_data)); + + +bool torture_suite_init_tcase(struct torture_suite *suite, + struct torture_tcase *tcase, + const char *name); + +struct torture_context *torture_context_init(struct event_context *event_ctx, + const struct torture_ui_ops *ui_ops); + +#endif /* __TORTURE_UI_H__ */ diff --git a/source4/lib/util/tests/str.c b/source4/lib/util/tests/str.c index a219ef0891..3bd6a02fdc 100644 --- a/source4/lib/util/tests/str.c +++ b/source4/lib/util/tests/str.c @@ -20,7 +20,7 @@ */ #include "includes.h" -#include "torture/ui.h" +#include "torture/torture.h" static bool test_string_sub_simple(struct torture_context *tctx) { diff --git a/source4/torture/basic/base.c b/source4/torture/basic/base.c index 966d436935..2ab3f9ca91 100644 --- a/source4/torture/basic/base.c +++ b/source4/torture/basic/base.c @@ -19,7 +19,7 @@ */ #include "includes.h" -#include "torture/torture.h" +#include "torture/smbtorture.h" #include "torture/basic/proto.h" #include "libcli/libcli.h" #include "libcli/raw/raw_proto.h" diff --git a/source4/torture/basic/locking.c b/source4/torture/basic/locking.c index 2e2585b976..3f399c97ef 100644 --- a/source4/torture/basic/locking.c +++ b/source4/torture/basic/locking.c @@ -23,9 +23,8 @@ #include "includes.h" #include "libcli/raw/libcliraw.h" #include "libcli/libcli.h" -#include "torture/ui.h" +#include "torture/smbtorture.h" #include "torture/util.h" -#include "torture/torture.h" #include "system/time.h" #include "system/filesys.h" diff --git a/source4/torture/basic/misc.c b/source4/torture/basic/misc.c index 188fc1bc69..24e0324bc3 100644 --- a/source4/torture/basic/misc.c +++ b/source4/torture/basic/misc.c @@ -30,7 +30,7 @@ #include "libcli/resolve/resolve.h" #include "auth/credentials/credentials.h" #include "librpc/gen_ndr/ndr_nbt.h" -#include "torture/torture.h" +#include "torture/smbtorture.h" #include "torture/util.h" #include "libcli/smb_composite/smb_composite.h" #include "libcli/composite/composite.h" diff --git a/source4/torture/config.mk b/source4/torture/config.mk index 1565797609..40f6bbf1ed 100644 --- a/source4/torture/config.mk +++ b/source4/torture/config.mk @@ -1,17 +1,3 @@ -# TORTURE subsystem -[LIBRARY::torture] -PRIVATE_PROTO_HEADER = proto.h -PUBLIC_DEPENDENCIES = \ - LIBSAMBA-HOSTCONFIG \ - LIBSAMBA-UTIL \ - LIBTALLOC \ - LIBPOPT - -PC_FILES += torture/torture.pc -torture_OBJ_FILES = $(addprefix torture/, torture.o ui.o) - -PUBLIC_HEADERS += torture/torture.h torture/ui.h - [SUBSYSTEM::TORTURE_UTIL] PRIVATE_DEPENDENCIES = LIBCLI_RAW LIBPYTHON smbcalls PROVISION PUBLIC_DEPENDENCIES = POPT_CREDENTIALS @@ -255,8 +241,9 @@ PRIVATE_DEPENDENCIES = \ # End BINARY smbtorture ################################# -smbtorture_OBJ_FILES = torture/smbtorture.o +smbtorture_OBJ_FILES = torture/smbtorture.o torture/torture.o +PUBLIC_HEADERS += torture/smbtorture.h MANPAGES += torture/man/smbtorture.1 ################################# diff --git a/source4/torture/ldap/common.c b/source4/torture/ldap/common.c index 5913163822..2c11de729c 100644 --- a/source4/torture/ldap/common.c +++ b/source4/torture/ldap/common.c @@ -22,7 +22,7 @@ #include "includes.h" #include "libcli/ldap/ldap_client.h" -#include "torture/torture.h" +#include "torture/smbtorture.h" #include "torture/ldap/proto.h" NTSTATUS torture_ldap_bind(struct ldap_connection *conn, const char *userdn, const char *password) diff --git a/source4/torture/libnet/libnet.c b/source4/torture/libnet/libnet.c index 3a75ffcae3..8c8353e8d6 100644 --- a/source4/torture/libnet/libnet.c +++ b/source4/torture/libnet/libnet.c @@ -18,7 +18,7 @@ */ #include "includes.h" -#include "torture/torture.h" +#include "torture/smbtorture.h" #include "librpc/rpc/dcerpc.h" #include "librpc/gen_ndr/security.h" #include "librpc/gen_ndr/lsa.h" diff --git a/source4/torture/local/dbspeed.c b/source4/torture/local/dbspeed.c index bf88c00e35..017c8568f4 100644 --- a/source4/torture/local/dbspeed.c +++ b/source4/torture/local/dbspeed.c @@ -26,7 +26,7 @@ #include "lib/ldb/include/ldb_errors.h" #include "lib/ldb_wrap.h" #include "lib/tdb_wrap.h" -#include "torture/torture.h" +#include "torture/smbtorture.h" #include "param/param.h" float tdb_speed; diff --git a/source4/torture/local/local.c b/source4/torture/local/local.c index e4dfadd3d1..1c3274adcd 100644 --- a/source4/torture/local/local.c +++ b/source4/torture/local/local.c @@ -18,7 +18,7 @@ */ #include "includes.h" -#include "torture/torture.h" +#include "torture/smbtorture.h" #include "torture/local/proto.h" #include "torture/ndr/ndr.h" #include "torture/ndr/proto.h" diff --git a/source4/torture/nbench/nbench.c b/source4/torture/nbench/nbench.c index e9bd32cce0..96144c4773 100644 --- a/source4/torture/nbench/nbench.c +++ b/source4/torture/nbench/nbench.c @@ -19,9 +19,8 @@ #include "includes.h" #include "libcli/libcli.h" -#include "torture/ui.h" #include "torture/util.h" -#include "torture/torture.h" +#include "torture/smbtorture.h" #include "system/filesys.h" #include "system/locale.h" #include "pstring.h" diff --git a/source4/torture/nbt/nbt.c b/source4/torture/nbt/nbt.c index d27a26eb30..422261884f 100644 --- a/source4/torture/nbt/nbt.c +++ b/source4/torture/nbt/nbt.c @@ -21,7 +21,7 @@ #include "libcli/nbt/libnbt.h" #include "torture/torture.h" #include "torture/nbt/proto.h" -#include "torture/ui.h" +#include "torture/smbtorture.h" #include "libcli/resolve/resolve.h" #include "param/param.h" diff --git a/source4/torture/ndr/ndr.c b/source4/torture/ndr/ndr.c index 55b00d1fb8..63636f8c5f 100644 --- a/source4/torture/ndr/ndr.c +++ b/source4/torture/ndr/ndr.c @@ -21,7 +21,7 @@ #include "includes.h" #include "torture/ndr/ndr.h" #include "torture/ndr/proto.h" -#include "torture/ui.h" +#include "torture/torture.h" #include "util/dlinklist.h" #include "param/param.h" diff --git a/source4/torture/rap/rap.c b/source4/torture/rap/rap.c index 4b5f4b582c..1ccd1254dd 100644 --- a/source4/torture/rap/rap.c +++ b/source4/torture/rap/rap.c @@ -21,7 +21,7 @@ #include "includes.h" #include "libcli/libcli.h" -#include "torture/torture.h" +#include "torture/smbtorture.h" #include "torture/util.h" #include "libcli/rap/rap.h" #include "libcli/raw/libcliraw.h" diff --git a/source4/torture/raw/lookuprate.c b/source4/torture/raw/lookuprate.c index 0e8f002efb..782cb1b31b 100644 --- a/source4/torture/raw/lookuprate.c +++ b/source4/torture/raw/lookuprate.c @@ -20,7 +20,7 @@ #include "includes.h" #include "param/param.h" #include "system/filesys.h" -#include "torture/torture.h" +#include "torture/smbtorture.h" #include "torture/basic/proto.h" #include "libcli/libcli.h" #include "torture/util.h" diff --git a/source4/torture/raw/raw.c b/source4/torture/raw/raw.c index 262ed1384b..c6133081b0 100644 --- a/source4/torture/raw/raw.c +++ b/source4/torture/raw/raw.c @@ -18,10 +18,10 @@ */ #include "includes.h" -#include "torture/torture.h" #include "libcli/raw/libcliraw.h" -#include "torture/raw/proto.h" #include "torture/util.h" +#include "torture/smbtorture.h" +#include "torture/raw/proto.h" NTSTATUS torture_raw_init(void) { diff --git a/source4/torture/rpc/rpc.c b/source4/torture/rpc/rpc.c index 7c8e78b160..fdb88b13dc 100644 --- a/source4/torture/rpc/rpc.c +++ b/source4/torture/rpc/rpc.c @@ -23,7 +23,7 @@ #include "lib/cmdline/popt_common.h" #include "librpc/rpc/dcerpc.h" #include "torture/rpc/rpc.h" -#include "torture/torture.h" +#include "torture/smbtorture.h" #include "librpc/ndr/ndr_table.h" #include "lib/util/dlinklist.h" diff --git a/source4/torture/rpc/rpc.h b/source4/torture/rpc/rpc.h index d0a0727787..48db814b7a 100644 --- a/source4/torture/rpc/rpc.h +++ b/source4/torture/rpc/rpc.h @@ -28,7 +28,7 @@ #include "librpc/rpc/dcerpc.h" #include "libcli/raw/libcliraw.h" #include "torture/rpc/proto.h" -#include "torture/ui.h" +#include "torture/torture.h" struct torture_rpc_tcase { struct torture_tcase tcase; diff --git a/source4/torture/rpc/spoolss_notify.c b/source4/torture/rpc/spoolss_notify.c index 19cff53d84..ab6309d55f 100644 --- a/source4/torture/rpc/spoolss_notify.c +++ b/source4/torture/rpc/spoolss_notify.c @@ -21,7 +21,6 @@ #include "includes.h" #include "torture/torture.h" -#include "torture/ui.h" #include "torture/rpc/rpc.h" #include "librpc/gen_ndr/ndr_spoolss_c.h" #include "rpc_server/dcerpc_server.h" diff --git a/source4/torture/rpc/spoolss_win.c b/source4/torture/rpc/spoolss_win.c index 9e2921d406..9ce9fb7526 100644 --- a/source4/torture/rpc/spoolss_win.c +++ b/source4/torture/rpc/spoolss_win.c @@ -20,7 +20,6 @@ #include "includes.h" #include "torture/torture.h" -#include "torture/ui.h" #include "torture/rpc/rpc.h" #include "librpc/gen_ndr/ndr_spoolss_c.h" #include "rpc_server/dcerpc_server.h" diff --git a/source4/torture/smb2/smb2.c b/source4/torture/smb2/smb2.c index f406b7d6e8..37eadcf7fd 100644 --- a/source4/torture/smb2/smb2.c +++ b/source4/torture/smb2/smb2.c @@ -21,7 +21,7 @@ #include "libcli/smb2/smb2.h" #include "libcli/smb2/smb2_calls.h" -#include "torture/torture.h" +#include "torture/smbtorture.h" #include "torture/smb2/proto.h" #include "lib/util/dlinklist.h" diff --git a/source4/torture/smbtorture.c b/source4/torture/smbtorture.c index 01a55a67f6..511f58cd7c 100644 --- a/source4/torture/smbtorture.c +++ b/source4/torture/smbtorture.c @@ -30,7 +30,7 @@ #include "lib/events/events.h" #include "dynconfig.h" -#include "torture/torture.h" +#include "torture/smbtorture.h" #include "build.h" #include "lib/util/dlinklist.h" #include "librpc/rpc/dcerpc.h" diff --git a/source4/torture/smbtorture.h b/source4/torture/smbtorture.h new file mode 100644 index 0000000000..3b5a573d83 --- /dev/null +++ b/source4/torture/smbtorture.h @@ -0,0 +1,40 @@ +/* + Unix SMB/CIFS implementation. + SMB torture tester + Copyright (C) Andrew Tridgell 1997-2003 + Copyright (C) Jelmer Vernooij 2006 + + 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 3 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, see . +*/ + +#ifndef __SMBTORTURE_H__ +#define __SMBTORTURE_H__ + +#include "torture/torture.h" + +struct smbcli_state; + +extern struct torture_suite *torture_root; + +extern int torture_entries; +extern int torture_seed; +extern int torture_numops; +extern int torture_failures; +extern int torture_numasync; + +struct torture_test; +int torture_init(void); +bool torture_register_suite(struct torture_suite *suite); + +#endif /* __SMBTORTURE_H__ */ diff --git a/source4/torture/torture.h b/source4/torture/torture.h deleted file mode 100644 index 26ecdb567b..0000000000 --- a/source4/torture/torture.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - Unix SMB/CIFS implementation. - SMB torture tester - Copyright (C) Andrew Tridgell 1997-2003 - Copyright (C) Jelmer Vernooij 2006 - - 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 3 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, see . -*/ - -#ifndef __TORTURE_H__ -#define __TORTURE_H__ - -#include "torture/ui.h" - -struct smbcli_state; - -extern struct torture_suite *torture_root; - -extern int torture_entries; -extern int torture_seed; -extern int torture_numops; -extern int torture_failures; -extern int torture_numasync; - -struct torture_test; -int torture_init(void); -bool torture_register_suite(struct torture_suite *suite); - - -#endif /* __TORTURE_H__ */ diff --git a/source4/torture/ui.c b/source4/torture/ui.c deleted file mode 100644 index abbd814747..0000000000 --- a/source4/torture/ui.c +++ /dev/null @@ -1,580 +0,0 @@ -/* - Unix SMB/CIFS implementation. - SMB torture UI functions - - Copyright (C) Jelmer Vernooij 2006 - - 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 3 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, see . -*/ - -#include "includes.h" -#include "torture/ui.h" -#include "torture/torture.h" -#include "lib/util/dlinklist.h" -#include "param/param.h" -#include "system/filesys.h" -#include "auth/credentials/credentials.h" -#include "lib/cmdline/popt_common.h" - -struct torture_context *torture_context_init(struct event_context *event_ctx, - const struct torture_ui_ops *ui_ops) -{ - struct torture_context *torture = talloc_zero(event_ctx, - struct torture_context); - torture->ui_ops = ui_ops; - torture->returncode = true; - torture->ev = event_ctx; - - if (ui_ops->init) - ui_ops->init(torture); - - return torture; -} - -/** - create a temporary directory. -*/ -_PUBLIC_ NTSTATUS torture_temp_dir(struct torture_context *tctx, - const char *prefix, - char **tempdir) -{ - SMB_ASSERT(tctx->outputdir != NULL); - - *tempdir = talloc_asprintf(tctx, "%s/%s.XXXXXX", tctx->outputdir, - prefix); - NT_STATUS_HAVE_NO_MEMORY(*tempdir); - - if (mkdtemp(*tempdir) == NULL) { - return map_nt_error_from_unix(errno); - } - - return NT_STATUS_OK; -} - -void torture_comment(struct torture_context *context, const char *comment, ...) -{ - va_list ap; - char *tmp; - - if (!context->ui_ops->comment) - return; - - va_start(ap, comment); - tmp = talloc_vasprintf(context, comment, ap); - - context->ui_ops->comment(context, tmp); - - talloc_free(tmp); -} - -void torture_warning(struct torture_context *context, const char *comment, ...) -{ - va_list ap; - char *tmp; - - if (!context->ui_ops->warning) - return; - - va_start(ap, comment); - tmp = talloc_vasprintf(context, comment, ap); - - context->ui_ops->warning(context, tmp); - - talloc_free(tmp); -} - -void torture_result(struct torture_context *context, - enum torture_result result, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - - if (context->last_reason) { - torture_warning(context, "%s", context->last_reason); - talloc_free(context->last_reason); - } - - context->last_result = result; - context->last_reason = talloc_vasprintf(context, fmt, ap); - va_end(ap); -} - -struct torture_suite *torture_suite_create(TALLOC_CTX *ctx, const char *name) -{ - struct torture_suite *suite = talloc_zero(ctx, struct torture_suite); - - suite->name = talloc_strdup(suite, name); - suite->testcases = NULL; - suite->children = NULL; - - return suite; -} - -void torture_tcase_set_fixture(struct torture_tcase *tcase, - bool (*setup) (struct torture_context *, void **), - bool (*teardown) (struct torture_context *, void *)) -{ - tcase->setup = setup; - tcase->teardown = teardown; -} - -static bool wrap_test_with_testcase_const(struct torture_context *torture_ctx, - struct torture_tcase *tcase, - struct torture_test *test) -{ - bool (*fn) (struct torture_context *, - const void *tcase_data, - const void *test_data); - - fn = test->fn; - - return fn(torture_ctx, tcase->data, test->data); -} - -struct torture_test *torture_tcase_add_test_const(struct torture_tcase *tcase, - const char *name, - bool (*run) (struct torture_context *, const void *tcase_data, - const void *test_data), - const void *data) -{ - struct torture_test *test = talloc(tcase, struct torture_test); - - test->name = talloc_strdup(test, name); - test->description = NULL; - test->run = wrap_test_with_testcase_const; - test->fn = run; - test->dangerous = false; - test->data = data; - - DLIST_ADD_END(tcase->tests, test, struct torture_test *); - - return test; -} - - -bool torture_suite_init_tcase(struct torture_suite *suite, - struct torture_tcase *tcase, - const char *name) -{ - tcase->name = talloc_strdup(tcase, name); - tcase->description = NULL; - tcase->setup = NULL; - tcase->teardown = NULL; - tcase->fixture_persistent = true; - tcase->tests = NULL; - - DLIST_ADD_END(suite->testcases, tcase, struct torture_tcase *); - - return true; -} - - -struct torture_tcase *torture_suite_add_tcase(struct torture_suite *suite, - const char *name) -{ - struct torture_tcase *tcase = talloc(suite, struct torture_tcase); - - if (!torture_suite_init_tcase(suite, tcase, name)) - return NULL; - - return tcase; -} - -bool torture_run_suite(struct torture_context *context, - struct torture_suite *suite) -{ - bool ret = true; - struct torture_tcase *tcase; - struct torture_suite *tsuite; - char *old_testname; - - context->level++; - if (context->ui_ops->suite_start) - context->ui_ops->suite_start(context, suite); - - old_testname = context->active_testname; - if (old_testname != NULL) - context->active_testname = talloc_asprintf(context, "%s-%s", - old_testname, suite->name); - else - context->active_testname = talloc_strdup(context, suite->name); - - for (tcase = suite->testcases; tcase; tcase = tcase->next) { - ret &= torture_run_tcase(context, tcase); - } - - for (tsuite = suite->children; tsuite; tsuite = tsuite->next) { - ret &= torture_run_suite(context, tsuite); - } - - talloc_free(context->active_testname); - context->active_testname = old_testname; - - if (context->ui_ops->suite_finish) - context->ui_ops->suite_finish(context, suite); - - context->level--; - - return ret; -} - -void torture_ui_test_start(struct torture_context *context, - struct torture_tcase *tcase, - struct torture_test *test) -{ - if (context->ui_ops->test_start) - context->ui_ops->test_start(context, tcase, test); -} - -int str_list_match(const char *name, char **list) -{ - int i, ret = 0; - if (list == NULL) - return 0; - - for (i = 0; list[i]; i++) { - if (gen_fnmatch(list[i], name) == 0) - ret++; - } - return ret; -} - -void torture_ui_test_result(struct torture_context *context, - enum torture_result result, - const char *comment) -{ - if (context->ui_ops->test_result) - context->ui_ops->test_result(context, result, comment); - - if (result == TORTURE_ERROR || result == TORTURE_FAIL) - context->returncode = false; -} - -static bool internal_torture_run_test(struct torture_context *context, - struct torture_tcase *tcase, - struct torture_test *test, - bool already_setup) -{ - bool success; - char *old_testname; - - if (tcase == NULL || strcmp(test->name, tcase->name) != 0) { - old_testname = context->active_testname; - context->active_testname = talloc_asprintf(context, "%s-%s", old_testname, test->name); - } - - context->active_tcase = tcase; - context->active_test = test; - - torture_ui_test_start(context, tcase, test); - - context->last_reason = NULL; - context->last_result = TORTURE_OK; - - if (!already_setup && tcase->setup && - !tcase->setup(context, &(tcase->data))) { - if (context->last_reason == NULL) - context->last_reason = talloc_strdup(context, "Setup failure"); - context->last_result = TORTURE_ERROR; - success = false; - } else if (test->dangerous && - !torture_setting_bool(context, "dangerous", false)) { - context->last_result = TORTURE_SKIP; - context->last_reason = talloc_asprintf(context, - "disabled %s - enable dangerous tests to use", test->name); - success = true; - } else { - success = test->run(context, tcase, test); - - if (!success && context->last_result == TORTURE_OK) { - if (context->last_reason == NULL) - context->last_reason = talloc_strdup(context, "Unknown error/failure"); - context->last_result = TORTURE_ERROR; - } - } - - if (!already_setup && tcase->teardown && !tcase->teardown(context, tcase->data)) { - if (context->last_reason == NULL) - context->last_reason = talloc_strdup(context, "Setup failure"); - context->last_result = TORTURE_ERROR; - success = false; - } - - torture_ui_test_result(context, context->last_result, - context->last_reason); - - talloc_free(context->last_reason); - - if (tcase == NULL || strcmp(test->name, tcase->name) != 0) { - talloc_free(context->active_testname); - context->active_testname = old_testname; - } - context->active_test = NULL; - context->active_tcase = NULL; - - return success; -} - -bool torture_run_tcase(struct torture_context *context, - struct torture_tcase *tcase) -{ - bool ret = true; - char *old_testname; - struct torture_test *test; - - context->level++; - - context->active_tcase = tcase; - if (context->ui_ops->tcase_start) - context->ui_ops->tcase_start(context, tcase); - - if (tcase->fixture_persistent && tcase->setup - && !tcase->setup(context, &tcase->data)) { - /* FIXME: Use torture ui ops for reporting this error */ - fprintf(stderr, "Setup failed: "); - if (context->last_reason != NULL) - fprintf(stderr, "%s", context->last_reason); - fprintf(stderr, "\n"); - ret = false; - goto done; - } - - old_testname = context->active_testname; - context->active_testname = talloc_asprintf(context, "%s-%s", - old_testname, tcase->name); - for (test = tcase->tests; test; test = test->next) { - ret &= internal_torture_run_test(context, tcase, test, - tcase->fixture_persistent); - } - talloc_free(context->active_testname); - context->active_testname = old_testname; - - if (tcase->fixture_persistent && tcase->teardown && - !tcase->teardown(context, tcase->data)) - ret = false; - -done: - context->active_tcase = NULL; - - if (context->ui_ops->tcase_finish) - context->ui_ops->tcase_finish(context, tcase); - - context->level--; - - return ret; -} - -bool torture_run_test(struct torture_context *context, - struct torture_tcase *tcase, - struct torture_test *test) -{ - return internal_torture_run_test(context, tcase, test, false); -} - -int torture_setting_int(struct torture_context *test, const char *name, - int default_value) -{ - return lp_parm_int(test->lp_ctx, NULL, "torture", name, default_value); -} - -double torture_setting_double(struct torture_context *test, const char *name, - double default_value) -{ - return lp_parm_double(test->lp_ctx, NULL, "torture", name, default_value); -} - -bool torture_setting_bool(struct torture_context *test, const char *name, - bool default_value) -{ - return lp_parm_bool(test->lp_ctx, NULL, "torture", name, default_value); -} - -const char *torture_setting_string(struct torture_context *test, - const char *name, - const char *default_value) -{ - const char *ret; - - SMB_ASSERT(test != NULL); - SMB_ASSERT(test->lp_ctx != NULL); - - ret = lp_parm_string(test->lp_ctx, NULL, "torture", name); - - if (ret == NULL) - return default_value; - - return ret; -} - -static bool wrap_test_with_simple_tcase_const ( - struct torture_context *torture_ctx, - struct torture_tcase *tcase, - struct torture_test *test) -{ - bool (*fn) (struct torture_context *, const void *tcase_data); - - fn = test->fn; - - return fn(torture_ctx, test->data); -} - -struct torture_tcase *torture_suite_add_simple_tcase_const( - struct torture_suite *suite, const char *name, - bool (*run) (struct torture_context *test, const void *), - const void *data) -{ - struct torture_tcase *tcase; - struct torture_test *test; - - tcase = torture_suite_add_tcase(suite, name); - - test = talloc(tcase, struct torture_test); - - test->name = talloc_strdup(test, name); - test->description = NULL; - test->run = wrap_test_with_simple_tcase_const; - test->fn = run; - test->data = data; - test->dangerous = false; - - DLIST_ADD_END(tcase->tests, test, struct torture_test *); - - return tcase; -} - -static bool wrap_simple_test(struct torture_context *torture_ctx, - struct torture_tcase *tcase, - struct torture_test *test) -{ - bool (*fn) (struct torture_context *); - - fn = test->fn; - - return fn(torture_ctx); -} - -struct torture_tcase *torture_suite_add_simple_test( - struct torture_suite *suite, - const char *name, - bool (*run) (struct torture_context *test)) -{ - struct torture_test *test; - struct torture_tcase *tcase; - - tcase = torture_suite_add_tcase(suite, name); - - test = talloc(tcase, struct torture_test); - - test->name = talloc_strdup(test, name); - test->description = NULL; - test->run = wrap_simple_test; - test->fn = run; - test->dangerous = false; - - DLIST_ADD_END(tcase->tests, test, struct torture_test *); - - return tcase; -} - -bool torture_suite_add_suite(struct torture_suite *suite, - struct torture_suite *child) -{ - if (child == NULL) - return false; - - DLIST_ADD_END(suite->children, child, struct torture_suite *); - - /* FIXME: Check for duplicates and return false if the - * added suite already exists as a child */ - - return true; -} - - -struct torture_suite *torture_find_suite(struct torture_suite *parent, - const char *name) -{ - struct torture_suite *child; - - for (child = parent->children; child; child = child->next) - if (!strcmp(child->name, name)) - return child; - - return NULL; -} - -static bool wrap_test_with_simple_test_const(struct torture_context *torture_ctx, - struct torture_tcase *tcase, - struct torture_test *test) -{ - bool (*fn) (struct torture_context *, const void *tcase_data); - - fn = test->fn; - - return fn(torture_ctx, tcase->data); -} - -struct torture_test *torture_tcase_add_simple_test_const( - struct torture_tcase *tcase, - const char *name, - bool (*run) (struct torture_context *test, - const void *tcase_data)) -{ - struct torture_test *test; - - test = talloc(tcase, struct torture_test); - - test->name = talloc_strdup(test, name); - test->description = NULL; - test->run = wrap_test_with_simple_test_const; - test->fn = run; - test->data = NULL; - test->dangerous = false; - - DLIST_ADD_END(tcase->tests, test, struct torture_test *); - - return test; -} - -static bool wrap_test_with_simple_test(struct torture_context *torture_ctx, - struct torture_tcase *tcase, - struct torture_test *test) -{ - bool (*fn) (struct torture_context *, void *tcase_data); - - fn = test->fn; - - return fn(torture_ctx, tcase->data); -} - -struct torture_test *torture_tcase_add_simple_test(struct torture_tcase *tcase, - const char *name, - bool (*run) (struct torture_context *test, void *tcase_data)) -{ - struct torture_test *test; - - test = talloc(tcase, struct torture_test); - - test->name = talloc_strdup(test, name); - test->description = NULL; - test->run = wrap_test_with_simple_test; - test->fn = run; - test->data = NULL; - test->dangerous = false; - - DLIST_ADD_END(tcase->tests, test, struct torture_test *); - - return test; -} diff --git a/source4/torture/ui.h b/source4/torture/ui.h deleted file mode 100644 index 15b04c2397..0000000000 --- a/source4/torture/ui.h +++ /dev/null @@ -1,396 +0,0 @@ -/* - Unix SMB/CIFS implementation. - SMB torture UI functions - - Copyright (C) Jelmer Vernooij 2006 - - 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 3 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, see . -*/ - -#ifndef __TORTURE_UI_H__ -#define __TORTURE_UI_H__ - -struct torture_test; -struct torture_context; -struct torture_suite; -struct torture_tcase; - -enum torture_result { - TORTURE_OK=0, - TORTURE_FAIL=1, - TORTURE_ERROR=2, - TORTURE_SKIP=3 -}; - -/* - * These callbacks should be implemented by any backend that wishes - * to listen to reports from the torture tests. - */ -struct torture_ui_ops -{ - void (*init) (struct torture_context *); - void (*comment) (struct torture_context *, const char *); - void (*warning) (struct torture_context *, const char *); - void (*suite_start) (struct torture_context *, struct torture_suite *); - void (*suite_finish) (struct torture_context *, struct torture_suite *); - void (*tcase_start) (struct torture_context *, struct torture_tcase *); - void (*tcase_finish) (struct torture_context *, struct torture_tcase *); - void (*test_start) (struct torture_context *, - struct torture_tcase *, - struct torture_test *); - void (*test_result) (struct torture_context *, - enum torture_result, const char *reason); -}; - -void torture_ui_test_start(struct torture_context *context, - struct torture_tcase *tcase, - struct torture_test *test); - -void torture_ui_test_result(struct torture_context *context, - enum torture_result result, - const char *comment); - -/* - * Holds information about a specific run of the testsuite. - * The data in this structure should be considered private to - * the torture tests and should only be used directly by the torture - * code and the ui backends. - * - * Torture tests should instead call the torture_*() macros and functions - * specified below. - */ - -struct torture_context -{ - const struct torture_ui_ops *ui_ops; - void *ui_data; - - char *active_testname; - struct torture_test *active_test; - struct torture_tcase *active_tcase; - - bool quiet; /* Whether tests should avoid writing output to stdout */ - - enum torture_result last_result; - char *last_reason; - - bool returncode; - - const char *outputdir; - int level; - struct event_context *ev; - - struct loadparm_context *lp_ctx; -}; - -/* - * Describes a particular torture test - */ -struct torture_test { - const char *name; - const char *description; - bool dangerous; - /* Function to call to run this test */ - bool (*run) (struct torture_context *torture_ctx, - struct torture_tcase *tcase, - struct torture_test *test); - - struct torture_test *prev, *next; - - /* Pointer to the actual test function. This is run by the - * run() function above. */ - void *fn; - const void *data; -}; - -/* - * Describes a particular test case. - */ -struct torture_tcase { - const char *name; - const char *description; - bool (*setup) (struct torture_context *tcase, void **data); - bool (*teardown) (struct torture_context *tcase, void *data); - bool fixture_persistent; - void *data; - struct torture_test *tests; - struct torture_tcase *prev, *next; -}; - -struct torture_suite -{ - const char *name; - const char *description; - struct torture_tcase *testcases; - struct torture_suite *children; - - /* Pointers to siblings of this torture suite */ - struct torture_suite *prev, *next; -}; - -/** Create a new torture suite */ -struct torture_suite *torture_suite_create(TALLOC_CTX *mem_ctx, - const char *name); - -/** Change the setup and teardown functions for a testcase */ -void torture_tcase_set_fixture(struct torture_tcase *tcase, - bool (*setup) (struct torture_context *, void **), - bool (*teardown) (struct torture_context *, void *)); - -/* Add another test to run for a particular testcase */ -struct torture_test *torture_tcase_add_test_const(struct torture_tcase *tcase, - const char *name, - bool (*run) (struct torture_context *test, - const void *tcase_data, const void *test_data), - const void *test_data); - -/* Add a testcase to a testsuite */ -struct torture_tcase *torture_suite_add_tcase(struct torture_suite *suite, - const char *name); - -/* Convenience wrapper that adds a testcase against only one - * test will be run */ -struct torture_tcase *torture_suite_add_simple_tcase_const( - struct torture_suite *suite, - const char *name, - bool (*run) (struct torture_context *test, - const void *test_data), - const void *data); - -/* Convenience function that adds a test which only - * gets the test case data */ -struct torture_test *torture_tcase_add_simple_test_const( - struct torture_tcase *tcase, - const char *name, - bool (*run) (struct torture_context *test, - const void *tcase_data)); - -/* Convenience wrapper that adds a test that doesn't need any - * testcase data */ -struct torture_tcase *torture_suite_add_simple_test( - struct torture_suite *suite, - const char *name, - bool (*run) (struct torture_context *test)); - -/* Add a child testsuite to an existing testsuite */ -bool torture_suite_add_suite(struct torture_suite *suite, - struct torture_suite *child); - -/* Run the specified testsuite recursively */ -bool torture_run_suite(struct torture_context *context, - struct torture_suite *suite); - -/* Run the specified testcase */ -bool torture_run_tcase(struct torture_context *context, - struct torture_tcase *tcase); - -/* Run the specified test */ -bool torture_run_test(struct torture_context *context, - struct torture_tcase *tcase, - struct torture_test *test); - -void torture_comment(struct torture_context *test, const char *comment, ...) PRINTF_ATTRIBUTE(2,3); -void torture_warning(struct torture_context *test, const char *comment, ...) PRINTF_ATTRIBUTE(2,3); -void torture_result(struct torture_context *test, - enum torture_result, const char *reason, ...) PRINTF_ATTRIBUTE(3,4); - -#define torture_assert(torture_ctx,expr,cmt) \ - if (!(expr)) { \ - torture_result(torture_ctx, TORTURE_FAIL, __location__": Expression `%s' failed: %s", __STRING(expr), cmt); \ - return false; \ - } - -#define torture_assert_werr_equal(torture_ctx, got, expected, cmt) \ - do { WERROR __got = got, __expected = expected; \ - if (!W_ERROR_EQUAL(__got, __expected)) { \ - torture_result(torture_ctx, TORTURE_FAIL, __location__": "#got" was %s, expected %s: %s", win_errstr(__got), win_errstr(__expected), cmt); \ - return false; \ - } \ - } while (0) - -#define torture_assert_ntstatus_equal(torture_ctx,got,expected,cmt) \ - do { NTSTATUS __got = got, __expected = expected; \ - if (!NT_STATUS_EQUAL(__got, __expected)) { \ - torture_result(torture_ctx, TORTURE_FAIL, __location__": "#got" was %s, expected %s: %s", nt_errstr(__got), nt_errstr(__expected), cmt); \ - return false; \ - }\ - } while(0) - -#define torture_assert_ndr_err_equal(torture_ctx,got,expected,cmt) \ - do { enum ndr_err_code __got = got, __expected = expected; \ - if (__got != __expected) { \ - torture_result(torture_ctx, TORTURE_FAIL, __location__": "#got" was %d, expected %d (%s): %s", __got, __expected, __STRING(expected), cmt); \ - return false; \ - }\ - } while(0) - -#define torture_assert_casestr_equal(torture_ctx,got,expected,cmt) \ - do { const char *__got = (got), *__expected = (expected); \ - if (!strequal(__got, __expected)) { \ - torture_result(torture_ctx, TORTURE_FAIL, __location__": "#got" was %s, expected %s: %s", __got, __expected, cmt); \ - return false; \ - } \ - } while(0) - -#define torture_assert_str_equal(torture_ctx,got,expected,cmt)\ - do { const char *__got = (got), *__expected = (expected); \ - if (strcmp_safe(__got, __expected) != 0) { \ - torture_result(torture_ctx, TORTURE_FAIL, \ - __location__": "#got" was %s, expected %s: %s", \ - __got, __expected, cmt); \ - return false; \ - } \ - } while(0) - -#define torture_assert_mem_equal(torture_ctx,got,expected,len,cmt)\ - do { const void *__got = (got), *__expected = (expected); \ - if (memcmp(__got, __expected, len) != 0) { \ - torture_result(torture_ctx, TORTURE_FAIL, \ - __location__": "#got" of len %d did not match"#expected": %s", len, cmt); \ - return false; \ - } \ - } while(0) - -#define torture_assert_file_contains_text(torture_ctx,filename,expected,cmt)\ - do { \ - char *__got; \ - const char *__expected = (expected); \ - size_t __size; \ - __got = file_load(filename, &__size, torture_ctx); \ - if (__got == NULL) { \ - torture_result(torture_ctx, TORTURE_FAIL, \ - __location__": unable to open %s: %s\n", \ - filename, cmt); \ - return false; \ - } \ - \ - if (strcmp_safe(__got, __expected) != 0) { \ - torture_result(torture_ctx, TORTURE_FAIL, \ - __location__": %s contained:\n%sExpected: %s%s\n", \ - filename, __got, __expected, cmt); \ - talloc_free(__got); \ - return false; \ - } \ - talloc_free(__got); \ - } while(0) - -#define torture_assert_file_contains(torture_ctx,filename,expected,cmt)\ - do { const char *__got, *__expected = (expected); \ - size_t __size; \ - __got = file_load(filename, *size, torture_ctx); \ - if (strcmp_safe(__got, __expected) != 0) { \ - torture_result(torture_ctx, TORTURE_FAIL, \ - __location__": %s contained:\n%sExpected: %s%s\n", \ - __got, __expected, cmt); \ - talloc_free(__got); \ - return false; \ - } \ - talloc_free(__got); \ - } while(0) - -#define torture_assert_int_equal(torture_ctx,got,expected,cmt)\ - do { int __got = (got), __expected = (expected); \ - if (__got != __expected) { \ - torture_result(torture_ctx, TORTURE_FAIL, \ - __location__": "#got" was %d, expected %d: %s", \ - __got, __expected, cmt); \ - return false; \ - } \ - } while(0) - -#define torture_assert_u64_equal(torture_ctx,got,expected,cmt)\ - do { uint64_t __got = (got), __expected = (expected); \ - if (__got != __expected) { \ - torture_result(torture_ctx, TORTURE_FAIL, \ - __location__": "#got" was %llu, expected %llu: %s", \ - (unsigned long long)__got, (unsigned long long)__expected, cmt); \ - return false; \ - } \ - } while(0) - -#define torture_assert_errno_equal(torture_ctx,expected,cmt)\ - do { int __expected = (expected); \ - if (errno != __expected) { \ - torture_result(torture_ctx, TORTURE_FAIL, \ - __location__": errno was %d (%s), expected %d: %s: %s", \ - errno, strerror(errno), __expected, \ - strerror(__expected), cmt); \ - return false; \ - } \ - } while(0) - - - -#define torture_skip(torture_ctx,cmt) do {\ - torture_result(torture_ctx, TORTURE_SKIP, __location__": %s", cmt);\ - return true; \ - } while(0) -#define torture_fail(torture_ctx,cmt) do {\ - torture_result(torture_ctx, TORTURE_FAIL, __location__": %s", cmt);\ - return false; \ - } while (0) -#define torture_fail_goto(torture_ctx,label,cmt) do {\ - torture_result(torture_ctx, TORTURE_FAIL, __location__": %s", cmt);\ - goto label; \ - } while (0) - -#define torture_out stderr - -/* Convenience macros */ -#define torture_assert_ntstatus_ok(torture_ctx,expr,cmt) \ - torture_assert_ntstatus_equal(torture_ctx,expr,NT_STATUS_OK,cmt) - -#define torture_assert_werr_ok(torture_ctx,expr,cmt) \ - torture_assert_werr_equal(torture_ctx,expr,WERR_OK,cmt) - -#define torture_assert_ndr_success(torture_ctx,expr,cmt) \ - torture_assert_ndr_err_equal(torture_ctx,expr,NDR_ERR_SUCCESS,cmt) - -/* Getting settings */ -const char *torture_setting_string(struct torture_context *test, \ - const char *name, - const char *default_value); - -int torture_setting_int(struct torture_context *test, - const char *name, - int default_value); - -double torture_setting_double(struct torture_context *test, - const char *name, - double default_value); - -bool torture_setting_bool(struct torture_context *test, - const char *name, - bool default_value); - -struct torture_suite *torture_find_suite(struct torture_suite *parent, - const char *name); - -NTSTATUS torture_temp_dir(struct torture_context *tctx, - const char *prefix, - char **tempdir); - -struct torture_test *torture_tcase_add_simple_test(struct torture_tcase *tcase, - const char *name, - bool (*run) (struct torture_context *test, void *tcase_data)); - - -bool torture_suite_init_tcase(struct torture_suite *suite, - struct torture_tcase *tcase, - const char *name); - -struct torture_context *torture_context_init(struct event_context *event_ctx, - const struct torture_ui_ops *ui_ops); - -#endif /* __TORTURE_UI_H__ */ diff --git a/source4/torture/unix/unix.c b/source4/torture/unix/unix.c index 05ea27db02..661e337270 100644 --- a/source4/torture/unix/unix.c +++ b/source4/torture/unix/unix.c @@ -18,7 +18,7 @@ */ #include "includes.h" -#include "torture/torture.h" +#include "torture/smbtorture.h" #include "torture/unix/proto.h" NTSTATUS torture_unix_init(void) diff --git a/source4/torture/util.h b/source4/torture/util.h index 1009fcf9f1..9dc948ade5 100644 --- a/source4/torture/util.h +++ b/source4/torture/util.h @@ -20,6 +20,11 @@ #ifndef _TORTURE_PROVISION_H_ #define _TORTURE_PROVISION_H_ +#include "torture/torture.h" + +struct smbcli_state; +struct smbcli_tree; + /** setup a directory ready for a test */ diff --git a/source4/torture/util_smb.c b/source4/torture/util_smb.c index c1a20094f3..938e7d6c03 100644 --- a/source4/torture/util_smb.c +++ b/source4/torture/util_smb.c @@ -28,7 +28,6 @@ #include "system/shmem.h" #include "system/wait.h" #include "system/time.h" -#include "torture/ui.h" #include "torture/torture.h" #include "util/dlinklist.h" #include "auth/credentials/credentials.h" diff --git a/source4/torture/winbind/winbind.c b/source4/torture/winbind/winbind.c index e283602337..b12e92552e 100644 --- a/source4/torture/winbind/winbind.c +++ b/source4/torture/winbind/winbind.c @@ -18,7 +18,7 @@ */ #include "includes.h" -#include "torture/torture.h" +#include "torture/smbtorture.h" #include "torture/winbind/proto.h" NTSTATUS torture_winbind_init(void) -- cgit From 86a22b6fad4c99db10f25a9d454e1ce9e7fdb5c4 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 27 Apr 2008 15:04:33 +0100 Subject: Fix header locations. (This used to be commit 4fc11bd97d6b65569742a7f1c695b7ecbc76919a) --- source4/headermap.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source4/headermap.txt b/source4/headermap.txt index fbfc56e127..bbd0d3c866 100644 --- a/source4/headermap.txt +++ b/source4/headermap.txt @@ -44,7 +44,7 @@ rpc_server/common/common.h: dcerpc_server/common.h libcli/auth/credentials.h: domain_credentials.h lib/charset/charset.h: charset.h libcli/ldap/ldap.h: ldap.h -torture/torture.h: torture.h +lib/torture/torture.h: torture.h libcli/libcli.h: client.h librpc/gen_ndr/nbt.h: gen_ndr/nbt.h librpc/gen_ndr/svcctl.h: gen_ndr/svcctl.h @@ -60,7 +60,7 @@ lib/util/asn1.h: samba/asn1.h libcli/util/error.h: core/error.h lib/tdb_wrap.h: tdb_wrap.h lib/ldb_wrap.h: ldb_wrap.h -torture/ui.h: torture/ui.h +torture/smbtorture.h: smbtorture.h librpc/gen_ndr/winbind.h: gen_ndr/winbind.h param/share.h: share.h lib/util/util_tdb.h: util_tdb.h -- cgit From aedaba990f02fd1f613c1830d3774843cf8d5f0d Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 27 Apr 2008 23:29:50 +0100 Subject: Split up lcov target. (This used to be commit 38f455e0054acc1fdaea267e03f8aad337309cf2) --- source4/torture/config.mk | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/source4/torture/config.mk b/source4/torture/config.mk index 40f6bbf1ed..4113cab064 100644 --- a/source4/torture/config.mk +++ b/source4/torture/config.mk @@ -327,9 +327,14 @@ gcov: test do $(GCOV) -p -o $$I $$I/*.c; \ done -lcov: test +samba.info: test -rm heimdal/lib/*/{lex,parse}.{gcda,gcno} lcov --base-directory `pwd` --directory . --capture --output-file samba.info - genhtml -o coverage samba.info + +lcov: samba.info + genhtml -o coverage $< testcov-html:: lcov + +clean:: + @rm -f samba.info -- cgit From f8fb5d8c4da11cdb8ac79649fd74047d4cc42c68 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 5 May 2008 12:57:23 +1000 Subject: Reorder this function in the file, so it reads bottom-up. The rest of this file reads bottom-up, but this function (connect_send_negprot()) was out of place. Andrew Bartlett (This used to be commit f0c95cd74fb6fea57cef89b59e5d2f10ea25c138) --- source4/libcli/smb_composite/connect.c | 37 +++++++++++++++++----------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/source4/libcli/smb_composite/connect.c b/source4/libcli/smb_composite/connect.c index 39c614f042..e56339f96b 100644 --- a/source4/libcli/smb_composite/connect.c +++ b/source4/libcli/smb_composite/connect.c @@ -58,25 +58,6 @@ struct connect_state { static void request_handler(struct smbcli_request *); static void composite_handler(struct composite_context *); -/* - setup a negprot send -*/ -static NTSTATUS connect_send_negprot(struct composite_context *c, - struct smb_composite_connect *io) -{ - struct connect_state *state = talloc_get_type(c->private_data, struct connect_state); - - state->req = smb_raw_negotiate_send(state->transport, io->in.options.unicode, io->in.options.max_protocol); - NT_STATUS_HAVE_NO_MEMORY(state->req); - - state->req->async.fn = request_handler; - state->req->async.private = c; - state->stage = CONNECT_NEGPROT; - - return NT_STATUS_OK; -} - - /* a tree connect request has completed */ @@ -291,6 +272,24 @@ static NTSTATUS connect_negprot(struct composite_context *c, return NT_STATUS_OK; } +/* + setup a negprot send +*/ +static NTSTATUS connect_send_negprot(struct composite_context *c, + struct smb_composite_connect *io) +{ + struct connect_state *state = talloc_get_type(c->private_data, struct connect_state); + + state->req = smb_raw_negotiate_send(state->transport, io->in.options.unicode, io->in.options.max_protocol); + NT_STATUS_HAVE_NO_MEMORY(state->req); + + state->req->async.fn = request_handler; + state->req->async.private = c; + state->stage = CONNECT_NEGPROT; + + return NT_STATUS_OK; +} + /* a session request operation has completed -- cgit From fe7d46067133131189faf7aebae62fa9c48626d9 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 5 May 2008 12:58:15 +1000 Subject: Allow an NTLM response to be specified into the auth subsystem. This allows it to be proxied for NTLM pass-though authentication (aka security=server and associated man-in-the-middle attacks). Andrew Bartlett (This used to be commit 6ffabb38d03ad90d8731ab3e0eb692438db967ee) --- source4/auth/credentials/credentials.c | 20 ++--------- source4/auth/credentials/credentials.h | 9 +++++ source4/auth/credentials/credentials_ntlm.c | 52 +++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 18 deletions(-) diff --git a/source4/auth/credentials/credentials.c b/source4/auth/credentials/credentials.c index bfed451689..adabe49cb4 100644 --- a/source4/auth/credentials/credentials.c +++ b/source4/auth/credentials/credentials.c @@ -306,6 +306,8 @@ _PUBLIC_ bool cli_credentials_set_password(struct cli_credentials *cred, cli_credentials_invalidate_ccache(cred, cred->password_obtained); cred->nt_hash = NULL; + cred->lm_response = data_blob(NULL, 0); + cred->nt_response = data_blob(NULL, 0); return true; } @@ -376,24 +378,6 @@ _PUBLIC_ const struct samr_Password *cli_credentials_get_nt_hash(struct cli_cred } } -_PUBLIC_ bool cli_credentials_set_nt_hash(struct cli_credentials *cred, - const struct samr_Password *nt_hash, - enum credentials_obtained obtained) -{ - if (obtained >= cred->password_obtained) { - cli_credentials_set_password(cred, NULL, obtained); - if (nt_hash) { - cred->nt_hash = talloc(cred, struct samr_Password); - *cred->nt_hash = *nt_hash; - } else { - cred->nt_hash = NULL; - } - return true; - } - - return false; -} - /** * Obtain the 'short' or 'NetBIOS' domain for this credentials context. * @param cred credentials context diff --git a/source4/auth/credentials/credentials.h b/source4/auth/credentials/credentials.h index 2514b5b1ce..79c50ae5af 100644 --- a/source4/auth/credentials/credentials.h +++ b/source4/auth/credentials/credentials.h @@ -80,8 +80,13 @@ struct cli_credentials { const char *bind_dn; + /* Allows authentication from a keytab or similar */ struct samr_Password *nt_hash; + /* Allows NTLM pass-though authentication */ + DATA_BLOB lm_response; + DATA_BLOB nt_response; + struct ccache_container *ccache; struct gssapi_creds_container *client_gss_creds; struct keytab_container *keytab; @@ -221,6 +226,10 @@ void cli_credentials_set_kvno(struct cli_credentials *cred, bool cli_credentials_set_nt_hash(struct cli_credentials *cred, const struct samr_Password *nt_hash, enum credentials_obtained obtained); +bool cli_credentials_set_ntlm_response(struct cli_credentials *cred, + const DATA_BLOB *lm_response, + const DATA_BLOB *nt_response, + enum credentials_obtained obtained); int cli_credentials_set_keytab_name(struct cli_credentials *cred, struct event_context *event_ctx, struct loadparm_context *lp_ctx, diff --git a/source4/auth/credentials/credentials_ntlm.c b/source4/auth/credentials/credentials_ntlm.c index b88f2018df..22e273c35a 100644 --- a/source4/auth/credentials/credentials_ntlm.c +++ b/source4/auth/credentials/credentials_ntlm.c @@ -52,6 +52,20 @@ _PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred const struct samr_Password *nt_hash; lm_session_key = data_blob(NULL, 0); + /* We may already have an NTLM response we prepared earlier. + * This is used for NTLM pass-though authentication */ + if (cred->nt_response.data || cred->lm_response.data) { + *_nt_response = cred->nt_response; + *_lm_response = cred->lm_response; + + if (!cred->lm_response.data) { + *flags = *flags & ~CLI_CRED_LANMAN_AUTH; + } + *_lm_session_key = data_blob(NULL, 0); + *_session_key = data_blob(NULL, 0); + return NT_STATUS_OK; + } + nt_hash = cli_credentials_get_nt_hash(cred, mem_ctx); cli_credentials_get_ntlm_username_domain(cred, mem_ctx, &user, &domain); @@ -215,3 +229,41 @@ _PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred return NT_STATUS_OK; } +_PUBLIC_ bool cli_credentials_set_nt_hash(struct cli_credentials *cred, + const struct samr_Password *nt_hash, + enum credentials_obtained obtained) +{ + if (obtained >= cred->password_obtained) { + cli_credentials_set_password(cred, NULL, obtained); + if (nt_hash) { + cred->nt_hash = talloc(cred, struct samr_Password); + *cred->nt_hash = *nt_hash; + } else { + cred->nt_hash = NULL; + } + return true; + } + + return false; +} + +_PUBLIC_ bool cli_credentials_set_ntlm_response(struct cli_credentials *cred, + const DATA_BLOB *lm_response, + const DATA_BLOB *nt_response, + enum credentials_obtained obtained) +{ + if (obtained >= cred->password_obtained) { + cli_credentials_set_password(cred, NULL, obtained); + if (nt_response) { + cred->nt_response = data_blob_talloc(cred, nt_response->data, nt_response->length); + talloc_steal(cred, cred->nt_response.data); + } + if (nt_response) { + cred->lm_response = data_blob_talloc(cred, lm_response->data, lm_response->length); + } + return true; + } + + return false; +} + -- cgit From 2c95244f1115c87a8ec3101427680a834d71ceaf Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 5 May 2008 13:21:18 +1000 Subject: Add a new implementation of security=server. This is not intended for general use, and will not be easily exposed (if I have anything to do with it), but should allow the CIFS proxy to re-use the connection. A work in progress. Andrew Bartlett (This used to be commit a1e60ebc6d1e794011df5f69f691f4ec8622e991) --- source4/auth/auth.c | 1 + source4/auth/auth_server.c | 494 ++++++++++++++++----------------------------- source4/auth/config.mk | 12 ++ 3 files changed, 184 insertions(+), 323 deletions(-) diff --git a/source4/auth/auth.c b/source4/auth/auth.c index 6c86cf2d7c..b74a438962 100644 --- a/source4/auth/auth.c +++ b/source4/auth/auth.c @@ -521,6 +521,7 @@ _PUBLIC_ NTSTATUS auth_init(void) extern NTSTATUS auth_anonymous_init(void); extern NTSTATUS auth_unix_init(void); extern NTSTATUS auth_sam_init(void); + extern NTSTATUS auth_server_init(void); init_module_fn static_init[] = { STATIC_auth_MODULES }; diff --git a/source4/auth/auth_server.c b/source4/auth/auth_server.c index f200ad9665..be5f84fe39 100644 --- a/source4/auth/auth_server.c +++ b/source4/auth/auth_server.c @@ -1,9 +1,10 @@ /* Unix SMB/CIFS implementation. - Authenticate to a remote server - Copyright (C) Andrew Tridgell 1992-1998 - Copyright (C) Andrew Bartlett 2001 - + Authenticate by using a remote server + Copyright (C) Andrew Bartlett 2001-2002, 2008 + Copyright (C) Jelmer Vernooij 2002 + Copyright (C) Stefan Metzmacher 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 3 of the License, or @@ -19,359 +20,206 @@ */ #include "includes.h" - -/**************************************************************************** - Support for server level security. -****************************************************************************/ - -static struct smbcli_state *server_cryptkey(TALLOC_CTX *mem_ctx, bool unicode, int maxprotocol, struct resolve_context *resolve_ctx) +#include "auth/auth.h" +#include "auth/auth_proto.h" +#include "auth/credentials/credentials.h" +#include "libcli/security/security.h" +#include "librpc/gen_ndr/ndr_samr.h" +#include "libcli/smb_composite/smb_composite.h" +#include "param/param.h" +#include "libcli/resolve/resolve.h" + +/* This version of 'security=server' rewirtten from scratch for Samba4 + * libraries in 2008 */ + + +static NTSTATUS server_want_check(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info) { - struct smbcli_state *cli = NULL; - fstring desthost; - struct in_addr dest_ip; - const char *p; - char *pserver; - bool connected_ok = false; - - if (!(cli = smbcli_initialise(cli))) - return NULL; - - /* security = server just can't function with spnego */ - cli->use_spnego = false; - - pserver = talloc_strdup(mem_ctx, lp_passwordserver()); - p = pserver; - - while(next_token( &p, desthost, LIST_SEP, sizeof(desthost))) { - strupper(desthost); - - if(!resolve_name(resolve_ctx, desthost, &dest_ip, 0x20)) { - DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",desthost)); - continue; - } - - if (ismyip(dest_ip)) { - DEBUG(1,("Password server loop - disabling password server %s\n",desthost)); - continue; - } - - /* we use a mutex to prevent two connections at once - when a - Win2k PDC get two connections where one hasn't completed a - session setup yet it will send a TCP reset to the first - connection (tridge) */ - - if (!grab_server_mutex(desthost)) { - return NULL; - } - - if (smbcli_connect(cli, desthost, &dest_ip)) { - DEBUG(3,("connected to password server %s\n",desthost)); - connected_ok = true; - break; - } - } + return NT_STATUS_OK; +} +/** + * The challenge from the target server, when operating in security=server + **/ +static NTSTATUS server_get_challenge(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, DATA_BLOB *_blob) +{ + struct smb_composite_connect io; + struct smbcli_options smb_options; + const char **host_list; + NTSTATUS status; - if (!connected_ok) { - release_server_mutex(); - DEBUG(0,("password server not available\n")); - talloc_free(cli); - return NULL; - } + /* Make a connection to the target server, found by 'password server' in smb.conf */ - if (!attempt_netbios_session_request(cli, lp_netbios_name(), - desthost, &dest_ip)) { - release_server_mutex(); - DEBUG(1,("password server fails session request\n")); - talloc_free(cli); - return NULL; + lp_smbcli_options(ctx->auth_ctx->lp_ctx, &smb_options); + + /* Make a negprot, WITHOUT SPNEGO, so we get a challenge nice an easy */ + io.in.options.use_spnego = false; + + /* Hope we don't get * (the default), as this won't work... */ + host_list = lp_passwordserver(ctx->auth_ctx->lp_ctx); + if (!host_list) { + return NT_STATUS_INTERNAL_ERROR; } - - if (strequal(desthost,myhostname(mem_ctx))) { - exit_server("Password server loop!"); + io.in.dest_host = host_list[0]; + if (strequal(io.in.dest_host, "*")) { + return NT_STATUS_INTERNAL_ERROR; } - - DEBUG(3,("got session\n")); + io.in.dest_ports = lp_smb_ports(ctx->auth_ctx->lp_ctx); - if (!smbcli_negprot(cli, unicode, maxprotocol)) { - DEBUG(1,("%s rejected the negprot\n",desthost)); - release_server_mutex(); - talloc_free(cli); - return NULL; - } + io.in.called_name = strupper_talloc(mem_ctx, io.in.dest_host); - if (cli->protocol < PROTOCOL_LANMAN2 || - !(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) { - DEBUG(1,("%s isn't in user level security mode\n",desthost)); - release_server_mutex(); - talloc_free(cli); - return NULL; - } + /* We don't want to get as far as the session setup */ + io.in.credentials = NULL; + io.in.service = NULL; - /* Get the first session setup done quickly, to avoid silly - Win2k bugs. (The next connection to the server will kill - this one... - */ - - if (!smbcli_session_setup(cli, "", "", 0, "", 0, - "")) { - DEBUG(0,("%s rejected the initial session setup (%s)\n", - desthost, smbcli_errstr(cli))); - release_server_mutex(); - talloc_free(cli); - return NULL; - } - - release_server_mutex(); - - DEBUG(3,("password server OK\n")); - - return cli; -} + io.in.workgroup = ""; /* only used with SPNEGO, disabled above */ -/**************************************************************************** - Clean up our allocated cli. -****************************************************************************/ + io.in.options = smb_options; -static void free_server_private_data(void **private_data_pointer) -{ - struct smbcli_state **cli = (struct smbcli_state **)private_data_pointer; - if (*cli && (*cli)->initialised) { - talloc_free(*cli); + status = smb_composite_connect(&io, mem_ctx, lp_resolve_context(ctx->auth_ctx->lp_ctx), + ctx->auth_ctx->event_ctx); + if (!NT_STATUS_IS_OK(status)) { + *_blob = io.out.tree->session->transport->negotiate.secblob; + ctx->private_data = talloc_steal(ctx, io.out.tree->session); } + return NT_STATUS_OK; } -/**************************************************************************** - Get the challenge out of a password server. -****************************************************************************/ - -static DATA_BLOB auth_get_challenge_server(const struct auth_context *auth_context, - void **my_private_data, - TALLOC_CTX *mem_ctx) +/** + * Return an error based on username + * + * This function allows the testing of obsure errors, as well as the generation + * of NT_STATUS -> DOS error mapping tables. + * + * This module is of no value to end-users. + * + * The password is ignored. + * + * @return An NTSTATUS value based on the username + **/ + +static NTSTATUS server_check_password(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info, + struct auth_serversupplied_info **_server_info) { - struct smbcli_state *cli = server_cryptkey(mem_ctx, lp_cli_maxprotocol(auth_context->lp_ctx)); + NTSTATUS nt_status; + struct auth_serversupplied_info *server_info; + struct cli_credentials *creds; + const char *user; + struct smb_composite_sesssetup session_setup; + + struct smbcli_session *session = talloc_get_type(ctx->private_data, struct smbcli_session); + + creds = cli_credentials_init(mem_ctx); + + NT_STATUS_HAVE_NO_MEMORY(creds); - if (cli) { - DEBUG(3,("using password server validation\n")); - - if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) { - /* We can't work with unencrypted password servers - unless 'encrypt passwords = no' */ - DEBUG(5,("make_auth_info_server: Server is unencrypted, no challenge available..\n")); - - /* However, it is still a perfectly fine connection - to pass that unencrypted password over */ - *my_private_data = (void *)cli; - return data_blob(NULL, 0); - - } else if (cli->secblob.length < 8) { - /* We can't do much if we don't get a full challenge */ - DEBUG(2,("make_auth_info_server: Didn't receive a full challenge from server\n")); - talloc_free(cli); - return data_blob(NULL, 0); - } - - *my_private_data = (void *)cli; - - /* The return must be allocated on the caller's mem_ctx, as our own will be - destoyed just after the call. */ - return data_blob_talloc(auth_context->mem_ctx, cli->secblob.data,8); - } else { - return data_blob(NULL, 0); + cli_credentials_set_username(creds, user_info->client.account_name, CRED_SPECIFIED); + cli_credentials_set_domain(creds, user_info->client.domain_name, CRED_SPECIFIED); + + switch (user_info->password_state) { + case AUTH_PASSWORD_PLAIN: + cli_credentials_set_password(creds, user_info->password.plaintext, + CRED_SPECIFIED); + break; + case AUTH_PASSWORD_HASH: + cli_credentials_set_nt_hash(creds, user_info->password.hash.nt, + CRED_SPECIFIED); + break; + + case AUTH_PASSWORD_RESPONSE: + cli_credentials_set_ntlm_response(creds, &user_info->password.response.lanman, &user_info->password.response.nt, CRED_SPECIFIED); + break; } -} + session_setup.in.sesskey = session->transport->negotiate.sesskey; + session_setup.in.capabilities = session->transport->negotiate.capabilities; -/**************************************************************************** - Check for a valid username and password in security=server mode. - - Validate a password with the password server. -****************************************************************************/ + session_setup.in.credentials = creds; + session_setup.in.workgroup = ""; /* Only used with SPNEGO, which we are not doing */ -static NTSTATUS check_smbserver_security(const struct auth_context *auth_context, - void *my_private_data, - TALLOC_CTX *mem_ctx, - const auth_usersupplied_info *user_info, - auth_serversupplied_info **server_info) -{ - struct smbcli_state *cli; - static uint8_t badpass[24]; - static fstring baduser; - static bool tested_password_server = false; - static bool bad_password_server = false; - NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE; - bool locally_made_cli = false; - - /* - * Check that the requested domain is not our own machine name. - * If it is, we should never check the PDC here, we use our own local - * password file. - */ - - if (lp_is_myname(auth_context->lp_ctx, user_info->domain.str)) { - DEBUG(3,("check_smbserver_security: Requested domain was for this machine.\n")); - return NT_STATUS_LOGON_FAILURE; - } + /* Check password with remove server - this should be async some day */ + nt_status = smb_composite_sesssetup(session, &session_setup); - cli = my_private_data; - - if (cli) { - } else { - cli = server_cryptkey(mem_ctx, lp_unicode(auth_context->lp_ctx), lp_cli_maxprotocol(auth_context->lp_ctx), lp_resolve_context(auth_context->lp_ctx)); - locally_made_cli = true; + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; } - if (!cli || !cli->initialised) { - DEBUG(1,("password server is not connected (cli not initilised)\n")); - return NT_STATUS_LOGON_FAILURE; - } - - if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) { - if (user_info->encrypted) { - DEBUG(1,("password server %s is plaintext, but we are encrypted. This just can't work :-(\n", cli->desthost)); - return NT_STATUS_LOGON_FAILURE; - } - } else { - if (memcmp(cli->secblob.data, auth_context->challenge.data, 8) != 0) { - DEBUG(1,("the challenge that the password server (%s) supplied us is not the one we gave our client. This just can't work :-(\n", cli->desthost)); - return NT_STATUS_LOGON_FAILURE; - } - } + server_info = talloc(mem_ctx, struct auth_serversupplied_info); + NT_STATUS_HAVE_NO_MEMORY(server_info); - if(badpass[0] == 0) - memset(badpass, 0x1f, sizeof(badpass)); + server_info->account_sid = dom_sid_parse_talloc(server_info, SID_NT_ANONYMOUS); + NT_STATUS_HAVE_NO_MEMORY(server_info->account_sid); - if((user_info->nt_resp.length == sizeof(badpass)) && - !memcmp(badpass, user_info->nt_resp.data, sizeof(badpass))) { - /* - * Very unlikely, our random bad password is the same as the users - * password. - */ - memset(badpass, badpass[0]+1, sizeof(badpass)); - } + /* is this correct? */ + server_info->primary_group_sid = dom_sid_parse_talloc(server_info, SID_BUILTIN_GUESTS); + NT_STATUS_HAVE_NO_MEMORY(server_info->primary_group_sid); - if(baduser[0] == 0) { - fstrcpy(baduser, INVALID_USER_PREFIX); - fstrcat(baduser, lp_netbios_name()); - } + server_info->n_domain_groups = 0; + server_info->domain_groups = NULL; - /* - * Attempt a session setup with a totally incorrect password. - * If this succeeds with the guest bit *NOT* set then the password - * server is broken and is not correctly setting the guest bit. We - * need to detect this as some versions of NT4.x are broken. JRA. - */ - - /* I sure as hell hope that there aren't servers out there that take - * NTLMv2 and have this bug, as we don't test for that... - * - abartlet@samba.org - */ - - if ((!tested_password_server) && (lp_paranoid_server_security())) { - if (smbcli_session_setup(cli, baduser, (char *)badpass, sizeof(badpass), - (char *)badpass, sizeof(badpass), user_info->domain.str)) { - - /* - * We connected to the password server so we - * can say we've tested it. - */ - tested_password_server = true; - - if ((SVAL(cli->inbuf,smb_vwv2) & 1) == 0) { - DEBUG(0,("server_validate: password server %s allows users as non-guest \ -with a bad password.\n", cli->desthost)); - DEBUG(0,("server_validate: This is broken (and insecure) behaviour. Please do not \ -use this machine as the password server.\n")); - smbcli_ulogoff(cli); - - /* - * Password server has the bug. - */ - bad_password_server = true; - return NT_STATUS_LOGON_FAILURE; - } - smbcli_ulogoff(cli); - } - } else { - - /* - * We have already tested the password server. - * Fail immediately if it has the bug. - */ - - if(bad_password_server) { - DEBUG(0,("server_validate: [1] password server %s allows users as non-guest \ -with a bad password.\n", cli->desthost)); - DEBUG(0,("server_validate: [1] This is broken (and insecure) behaviour. Please do not \ -use this machine as the password server.\n")); - return NT_STATUS_LOGON_FAILURE; - } - } + /* annoying, but the Anonymous really does have a session key, + and it is all zeros! */ + server_info->user_session_key = data_blob(NULL, 0); + server_info->lm_session_key = data_blob(NULL, 0); - /* - * Now we know the password server will correctly set the guest bit, or is - * not guest enabled, we can try with the real password. - */ - - if (!user_info->encrypted) { - /* Plaintext available */ - if (!smbcli_session_setup(cli, user_info->smb_name.str, - (char *)user_info->plaintext_password.data, - user_info->plaintext_password.length, - NULL, 0, - user_info->domain.str)) { - DEBUG(1,("password server %s rejected the password\n", cli->desthost)); - /* Make this smbcli_nt_error() when the conversion is in */ - nt_status = smbcli_nt_error(cli); - } else { - nt_status = NT_STATUS_OK; - } - } else { - if (!smbcli_session_setup(cli, user_info->smb_name.str, - (char *)user_info->lm_resp.data, - user_info->lm_resp.length, - (char *)user_info->nt_resp.data, - user_info->nt_resp.length, - user_info->domain.str)) { - DEBUG(1,("password server %s rejected the password\n", cli->desthost)); - /* Make this smbcli_nt_error() when the conversion is in */ - nt_status = smbcli_nt_error(cli); - } else { - nt_status = NT_STATUS_OK; - } - } + server_info->account_name = talloc_strdup(server_info, user_info->client.account_name); + NT_STATUS_HAVE_NO_MEMORY(server_info->account_name); - /* if logged in as guest then reject */ - if ((SVAL(cli->inbuf,smb_vwv2) & 1) != 0) { - DEBUG(1,("password server %s gave us guest only\n", cli->desthost)); - nt_status = NT_STATUS_LOGON_FAILURE; - } + server_info->domain_name = talloc_strdup(server_info, user_info->client.domain_name); + NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name); - smbcli_ulogoff(cli); + server_info->full_name = NULL; - if NT_STATUS_IS_OK(nt_status) { - struct passwd *pass = Get_Pwnam(user_info->internal_username.str); - if (pass) { - nt_status = make_server_info_pw(auth_context, server_info, pass); - } else { - nt_status = NT_STATUS_NO_SUCH_USER; - } - } + server_info->logon_script = talloc_strdup(server_info, ""); + NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script); - if (locally_made_cli) { - talloc_free(cli); - } + server_info->profile_path = talloc_strdup(server_info, ""); + NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path); + + server_info->home_directory = talloc_strdup(server_info, ""); + NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory); + + server_info->home_drive = talloc_strdup(server_info, ""); + NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive); + + server_info->last_logon = 0; + server_info->last_logoff = 0; + server_info->acct_expiry = 0; + server_info->last_password_change = 0; + server_info->allow_password_change = 0; + server_info->force_password_change = 0; + + server_info->logon_count = 0; + server_info->bad_password_count = 0; + + server_info->acct_flags = ACB_NORMAL; - return(nt_status); + server_info->authenticated = false; + + *_server_info = server_info; + + return nt_status; } -NTSTATUS auth_init_smbserver(struct auth_context *auth_context, const char* param, auth_methods **auth_method) +static const struct auth_operations server_auth_ops = { + .name = "server", + .get_challenge = server_get_challenge, + .want_check = server_want_check, + .check_password = server_check_password +}; + +_PUBLIC_ NTSTATUS auth_server_init(void) { - if (!make_auth_methods(auth_context, auth_method)) { - return NT_STATUS_NO_MEMORY; + NTSTATUS ret; + + ret = auth_register(&server_auth_ops); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(0,("Failed to register 'server' auth backend!\n")); + return ret; } - (*auth_method)->name = "smbserver"; - (*auth_method)->auth = check_smbserver_security; - (*auth_method)->get_chal = auth_get_challenge_server; - (*auth_method)->send_keepalive = send_server_keepalive; - (*auth_method)->free_private_data = free_server_private_data; - return NT_STATUS_OK; + + return ret; } diff --git a/source4/auth/config.mk b/source4/auth/config.mk index 7d4678b7ac..0acb9e30ba 100644 --- a/source4/auth/config.mk +++ b/source4/auth/config.mk @@ -54,6 +54,18 @@ SUBSYSTEM = auth auth_anonymous_OBJ_FILES = $(addprefix auth/, auth_anonymous.o) +####################### +# Start MODULE auth_anonymous +[MODULE::auth_server] +INIT_FUNCTION = auth_server_init +SUBSYSTEM = auth +PRIVATE_DEPENDENCIES = LIBSAMBA-UTIL LIBCLI_SMB +OUTPUT_TYPE = SHARED_LIBRARY +# End MODULE auth_server +####################### + +auth_server_OBJ_FILES = $(addprefix auth/, auth_server.o) + ####################### # Start MODULE auth_winbind [MODULE::auth_winbind] -- cgit From 7ee76eeae5b3e9e5f5b226039e7276897f5e6764 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 5 May 2008 15:23:57 +1000 Subject: Move NTLM authentication details into auth/ntlm This should help clarify the role of the various files around here (done on Jelmer's request). Andrew Bartlett (This used to be commit efa399037511ced8978f2e7661a71aac7a384883) --- source4/auth/auth.c | 539 ----------------------- source4/auth/auth_anonymous.c | 78 ---- source4/auth/auth_developer.c | 207 --------- source4/auth/auth_sam.c | 448 -------------------- source4/auth/auth_server.c | 225 ---------- source4/auth/auth_simple.c | 103 ----- source4/auth/auth_unix.c | 844 ------------------------------------- source4/auth/auth_util.c | 260 ------------ source4/auth/auth_winbind.c | 282 ------------- source4/auth/config.mk | 83 +--- source4/auth/ntlm/auth.c | 539 +++++++++++++++++++++++ source4/auth/ntlm/auth_anonymous.c | 78 ++++ source4/auth/ntlm/auth_developer.c | 207 +++++++++ source4/auth/ntlm/auth_proto.h | 50 +++ source4/auth/ntlm/auth_sam.c | 449 ++++++++++++++++++++ source4/auth/ntlm/auth_server.c | 225 ++++++++++ source4/auth/ntlm/auth_simple.c | 103 +++++ source4/auth/ntlm/auth_unix.c | 844 +++++++++++++++++++++++++++++++++++++ source4/auth/ntlm/auth_util.c | 260 ++++++++++++ source4/auth/ntlm/auth_winbind.c | 282 +++++++++++++ source4/auth/ntlm/config.mk | 87 ++++ source4/auth/ntlm/ntlm_check.c | 603 ++++++++++++++++++++++++++ source4/auth/ntlm/ntlm_check.h | 75 ++++ source4/auth/ntlm/pam_errors.c | 125 ++++++ source4/auth/ntlm/pam_errors.h | 39 ++ source4/auth/ntlm_check.c | 602 -------------------------- source4/auth/pam_errors.c | 125 ------ source4/utils/config.mk | 1 + source4/utils/ntlm_auth.c | 1 + 29 files changed, 3970 insertions(+), 3794 deletions(-) delete mode 100644 source4/auth/auth.c delete mode 100644 source4/auth/auth_anonymous.c delete mode 100644 source4/auth/auth_developer.c delete mode 100644 source4/auth/auth_sam.c delete mode 100644 source4/auth/auth_server.c delete mode 100644 source4/auth/auth_simple.c delete mode 100644 source4/auth/auth_unix.c delete mode 100644 source4/auth/auth_util.c delete mode 100644 source4/auth/auth_winbind.c create mode 100644 source4/auth/ntlm/auth.c create mode 100644 source4/auth/ntlm/auth_anonymous.c create mode 100644 source4/auth/ntlm/auth_developer.c create mode 100644 source4/auth/ntlm/auth_proto.h create mode 100644 source4/auth/ntlm/auth_sam.c create mode 100644 source4/auth/ntlm/auth_server.c create mode 100644 source4/auth/ntlm/auth_simple.c create mode 100644 source4/auth/ntlm/auth_unix.c create mode 100644 source4/auth/ntlm/auth_util.c create mode 100644 source4/auth/ntlm/auth_winbind.c create mode 100644 source4/auth/ntlm/config.mk create mode 100644 source4/auth/ntlm/ntlm_check.c create mode 100644 source4/auth/ntlm/ntlm_check.h create mode 100644 source4/auth/ntlm/pam_errors.c create mode 100644 source4/auth/ntlm/pam_errors.h delete mode 100644 source4/auth/ntlm_check.c delete mode 100644 source4/auth/pam_errors.c diff --git a/source4/auth/auth.c b/source4/auth/auth.c deleted file mode 100644 index b74a438962..0000000000 --- a/source4/auth/auth.c +++ /dev/null @@ -1,539 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Password and authentication handling - Copyright (C) Andrew Bartlett 2001-2002 - Copyright (C) Stefan Metzmacher 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 3 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, see . -*/ - -#include "includes.h" -#include "lib/util/dlinklist.h" -#include "auth/auth.h" -#include "auth/auth_proto.h" -#include "lib/events/events.h" -#include "build.h" -#include "param/param.h" - -/*************************************************************************** - Set a fixed challenge -***************************************************************************/ -_PUBLIC_ NTSTATUS auth_context_set_challenge(struct auth_context *auth_ctx, const uint8_t chal[8], const char *set_by) -{ - auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by); - NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by); - - auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8); - NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data); - - return NT_STATUS_OK; -} - -/*************************************************************************** - Set a fixed challenge -***************************************************************************/ -bool auth_challenge_may_be_modified(struct auth_context *auth_ctx) -{ - return auth_ctx->challenge.may_be_modified; -} - -/**************************************************************************** - Try to get a challenge out of the various authentication modules. - Returns a const char of length 8 bytes. -****************************************************************************/ -_PUBLIC_ NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, const uint8_t **_chal) -{ - NTSTATUS nt_status; - struct auth_method_context *method; - - if (auth_ctx->challenge.data.length) { - DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n", - auth_ctx->challenge.set_by)); - *_chal = auth_ctx->challenge.data.data; - return NT_STATUS_OK; - } - - for (method = auth_ctx->methods; method; method = method->next) { - DATA_BLOB challenge = data_blob(NULL,0); - - nt_status = method->ops->get_challenge(method, auth_ctx, &challenge); - if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) { - continue; - } - - NT_STATUS_NOT_OK_RETURN(nt_status); - - if (challenge.length != 8) { - DEBUG(0, ("auth_get_challenge: invalid challenge (length %u) by mothod [%s]\n", - (unsigned)challenge.length, method->ops->name)); - return NT_STATUS_INTERNAL_ERROR; - } - - auth_ctx->challenge.data = challenge; - auth_ctx->challenge.set_by = method->ops->name; - - break; - } - - if (!auth_ctx->challenge.set_by) { - uint8_t chal[8]; - generate_random_buffer(chal, 8); - - auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8); - NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data); - auth_ctx->challenge.set_by = "random"; - - auth_ctx->challenge.may_be_modified = true; - } - - DEBUG(10,("auth_get_challenge: challenge set by %s\n", - auth_ctx->challenge.set_by)); - - *_chal = auth_ctx->challenge.data.data; - return NT_STATUS_OK; -} - -struct auth_check_password_sync_state { - bool finished; - NTSTATUS status; - struct auth_serversupplied_info *server_info; -}; - -static void auth_check_password_sync_callback(struct auth_check_password_request *req, - void *private_data) -{ - struct auth_check_password_sync_state *s = talloc_get_type(private_data, - struct auth_check_password_sync_state); - - s->finished = true; - s->status = auth_check_password_recv(req, s, &s->server_info); -} - -/** - * Check a user's Plaintext, LM or NTLM password. - * (sync version) - * - * Check a user's password, as given in the user_info struct and return various - * interesting details in the server_info struct. - * - * The return value takes precedence over the contents of the server_info - * struct. When the return is other than NT_STATUS_OK the contents - * of that structure is undefined. - * - * @param auth_ctx Supplies the challenges and some other data. - * Must be created with auth_context_create(), and the challenges should be - * filled in, either at creation or by calling the challenge geneation - * function auth_get_challenge(). - * - * @param user_info Contains the user supplied components, including the passwords. - * - * @param mem_ctx The parent memory context for the server_info structure - * - * @param server_info If successful, contains information about the authentication, - * including a SAM_ACCOUNT struct describing the user. - * - * @return An NTSTATUS with NT_STATUS_OK or an appropriate error. - * - **/ - -_PUBLIC_ NTSTATUS auth_check_password(struct auth_context *auth_ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info, - struct auth_serversupplied_info **server_info) -{ - struct auth_check_password_sync_state *sync_state; - NTSTATUS status; - - sync_state = talloc_zero(auth_ctx, struct auth_check_password_sync_state); - NT_STATUS_HAVE_NO_MEMORY(sync_state); - - auth_check_password_send(auth_ctx, user_info, auth_check_password_sync_callback, sync_state); - - while (!sync_state->finished) { - event_loop_once(auth_ctx->event_ctx); - } - - status = sync_state->status; - - if (NT_STATUS_IS_OK(status)) { - *server_info = talloc_steal(mem_ctx, sync_state->server_info); - } - - talloc_free(sync_state); - return status; -} - -struct auth_check_password_request { - struct auth_context *auth_ctx; - const struct auth_usersupplied_info *user_info; - struct auth_serversupplied_info *server_info; - struct auth_method_context *method; - NTSTATUS status; - struct { - void (*fn)(struct auth_check_password_request *req, void *private_data); - void *private_data; - } callback; -}; - -static void auth_check_password_async_timed_handler(struct event_context *ev, struct timed_event *te, - struct timeval t, void *ptr) -{ - struct auth_check_password_request *req = talloc_get_type(ptr, struct auth_check_password_request); - req->status = req->method->ops->check_password(req->method, req, req->user_info, &req->server_info); - req->callback.fn(req, req->callback.private_data); -} - -/** - * Check a user's Plaintext, LM or NTLM password. - * async send hook - * - * Check a user's password, as given in the user_info struct and return various - * interesting details in the server_info struct. - * - * The return value takes precedence over the contents of the server_info - * struct. When the return is other than NT_STATUS_OK the contents - * of that structure is undefined. - * - * @param auth_ctx Supplies the challenges and some other data. - * Must be created with make_auth_context(), and the challenges should be - * filled in, either at creation or by calling the challenge geneation - * function auth_get_challenge(). - * - * @param user_info Contains the user supplied components, including the passwords. - * - * @param callback A callback function which will be called when the operation is finished. - * The callback function needs to call auth_check_password_recv() to get the return values - * - * @param private_data A private pointer which will ba passed to the callback function - * - **/ - -_PUBLIC_ void auth_check_password_send(struct auth_context *auth_ctx, - const struct auth_usersupplied_info *user_info, - void (*callback)(struct auth_check_password_request *req, void *private_data), - void *private_data) -{ - /* if all the modules say 'not for me' this is reasonable */ - NTSTATUS nt_status; - struct auth_method_context *method; - const uint8_t *challenge; - struct auth_usersupplied_info *user_info_tmp; - struct auth_check_password_request *req = NULL; - - DEBUG(3, ("auth_check_password_send: Checking password for unmapped user [%s]\\[%s]@[%s]\n", - user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name)); - - req = talloc_zero(auth_ctx, struct auth_check_password_request); - if (!req) { - callback(NULL, private_data); - return; - } - req->auth_ctx = auth_ctx; - req->user_info = user_info; - req->callback.fn = callback; - req->callback.private_data = private_data; - - if (!user_info->mapped_state) { - nt_status = map_user_info(req, lp_workgroup(auth_ctx->lp_ctx), user_info, &user_info_tmp); - if (!NT_STATUS_IS_OK(nt_status)) goto failed; - user_info = user_info_tmp; - req->user_info = user_info_tmp; - } - - DEBUGADD(3,("auth_check_password_send: mapped user is: [%s]\\[%s]@[%s]\n", - user_info->mapped.domain_name, user_info->mapped.account_name, user_info->workstation_name)); - - nt_status = auth_get_challenge(auth_ctx, &challenge); - if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(0, ("auth_check_password_send: Invalid challenge (length %u) stored for this auth context set_by %s - cannot continue: %s\n", - (unsigned)auth_ctx->challenge.data.length, auth_ctx->challenge.set_by, nt_errstr(nt_status))); - goto failed; - } - - if (auth_ctx->challenge.set_by) { - DEBUG(10, ("auth_check_password_send: auth_context challenge created by %s\n", - auth_ctx->challenge.set_by)); - } - - DEBUG(10, ("auth_check_password_send: challenge is: \n")); - dump_data(5, auth_ctx->challenge.data.data, auth_ctx->challenge.data.length); - - nt_status = NT_STATUS_NO_SUCH_USER; /* If all the modules say 'not for me', then this is reasonable */ - for (method = auth_ctx->methods; method; method = method->next) { - NTSTATUS result; - struct timed_event *te = NULL; - - /* check if the module wants to chek the password */ - result = method->ops->want_check(method, req, user_info); - if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) { - DEBUG(11,("auth_check_password_send: %s had nothing to say\n", method->ops->name)); - continue; - } - - nt_status = result; - req->method = method; - - if (!NT_STATUS_IS_OK(nt_status)) break; - - te = event_add_timed(auth_ctx->event_ctx, req, - timeval_zero(), - auth_check_password_async_timed_handler, req); - if (!te) { - nt_status = NT_STATUS_NO_MEMORY; - goto failed; - } - return; - } - -failed: - req->status = nt_status; - req->callback.fn(req, req->callback.private_data); -} - -/** - * Check a user's Plaintext, LM or NTLM password. - * async receive function - * - * The return value takes precedence over the contents of the server_info - * struct. When the return is other than NT_STATUS_OK the contents - * of that structure is undefined. - * - * - * @param req The async auth_check_password state, passes to the callers callback function - * - * @param mem_ctx The parent memory context for the server_info structure - * - * @param server_info If successful, contains information about the authentication, - * including a SAM_ACCOUNT struct describing the user. - * - * @return An NTSTATUS with NT_STATUS_OK or an appropriate error. - * - **/ - -_PUBLIC_ NTSTATUS auth_check_password_recv(struct auth_check_password_request *req, - TALLOC_CTX *mem_ctx, - struct auth_serversupplied_info **server_info) -{ - NTSTATUS status; - - NT_STATUS_HAVE_NO_MEMORY(req); - - if (NT_STATUS_IS_OK(req->status)) { - DEBUG(5,("auth_check_password_recv: %s authentication for user [%s\\%s] succeeded\n", - req->method->ops->name, req->server_info->domain_name, req->server_info->account_name)); - - *server_info = talloc_steal(mem_ctx, req->server_info); - } else { - DEBUG(2,("auth_check_password_recv: %s authentication for user [%s\\%s] FAILED with error %s\n", - (req->method ? req->method->ops->name : "NO_METHOD"), - req->user_info->mapped.domain_name, - req->user_info->mapped.account_name, - nt_errstr(req->status))); - } - - status = req->status; - talloc_free(req); - return status; -} - -/*************************************************************************** - Make a auth_info struct for the auth subsystem - - Allow the caller to specify the methods to use -***************************************************************************/ -_PUBLIC_ NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char **methods, - struct event_context *ev, - struct messaging_context *msg, - struct loadparm_context *lp_ctx, - struct auth_context **auth_ctx) -{ - int i; - struct auth_context *ctx; - - if (!methods) { - DEBUG(0,("auth_context_create: No auth method list!?\n")); - return NT_STATUS_INTERNAL_ERROR; - } - - if (!ev) { - DEBUG(0,("auth_context_create: called with out event context\n")); - return NT_STATUS_INTERNAL_ERROR; - } - - if (!msg) { - DEBUG(0,("auth_context_create: called with out messaging context\n")); - return NT_STATUS_INTERNAL_ERROR; - } - - ctx = talloc(mem_ctx, struct auth_context); - NT_STATUS_HAVE_NO_MEMORY(ctx); - ctx->challenge.set_by = NULL; - ctx->challenge.may_be_modified = false; - ctx->challenge.data = data_blob(NULL, 0); - ctx->methods = NULL; - ctx->event_ctx = ev; - ctx->msg_ctx = msg; - ctx->lp_ctx = lp_ctx; - - for (i=0; methods[i] ; i++) { - struct auth_method_context *method; - - method = talloc(ctx, struct auth_method_context); - NT_STATUS_HAVE_NO_MEMORY(method); - - method->ops = auth_backend_byname(methods[i]); - if (!method->ops) { - DEBUG(1,("auth_context_create: failed to find method=%s\n", - methods[i])); - return NT_STATUS_INTERNAL_ERROR; - } - method->auth_ctx = ctx; - method->depth = i; - DLIST_ADD_END(ctx->methods, method, struct auth_method_context *); - } - - if (!ctx->methods) { - return NT_STATUS_INTERNAL_ERROR; - } - - *auth_ctx = ctx; - - return NT_STATUS_OK; -} -/*************************************************************************** - Make a auth_info struct for the auth subsystem - - Uses default auth_methods, depending on server role and smb.conf settings -***************************************************************************/ -_PUBLIC_ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct messaging_context *msg, - struct loadparm_context *lp_ctx, - struct auth_context **auth_ctx) -{ - const char **auth_methods = NULL; - switch (lp_server_role(lp_ctx)) { - case ROLE_STANDALONE: - auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "standalone", NULL); - break; - case ROLE_DOMAIN_MEMBER: - auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "member server", NULL); - break; - case ROLE_DOMAIN_CONTROLLER: - auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "domain controller", NULL); - break; - } - return auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, auth_ctx); -} - - -/* the list of currently registered AUTH backends */ -static struct auth_backend { - const struct auth_operations *ops; -} *backends = NULL; -static int num_backends; - -/* - register a AUTH backend. - - The 'name' can be later used by other backends to find the operations - structure for this backend. -*/ -_PUBLIC_ NTSTATUS auth_register(const struct auth_operations *ops) -{ - struct auth_operations *new_ops; - - if (auth_backend_byname(ops->name) != NULL) { - /* its already registered! */ - DEBUG(0,("AUTH backend '%s' already registered\n", - ops->name)); - return NT_STATUS_OBJECT_NAME_COLLISION; - } - - backends = talloc_realloc(talloc_autofree_context(), backends, - struct auth_backend, num_backends+1); - NT_STATUS_HAVE_NO_MEMORY(backends); - - new_ops = talloc_memdup(backends, ops, sizeof(*ops)); - NT_STATUS_HAVE_NO_MEMORY(new_ops); - new_ops->name = talloc_strdup(new_ops, ops->name); - NT_STATUS_HAVE_NO_MEMORY(new_ops->name); - - backends[num_backends].ops = new_ops; - - num_backends++; - - DEBUG(3,("AUTH backend '%s' registered\n", - ops->name)); - - return NT_STATUS_OK; -} - -/* - return the operations structure for a named backend of the specified type -*/ -const struct auth_operations *auth_backend_byname(const char *name) -{ - int i; - - for (i=0;iname, name) == 0) { - return backends[i].ops; - } - } - - return NULL; -} - -/* - return the AUTH interface version, and the size of some critical types - This can be used by backends to either detect compilation errors, or provide - multiple implementations for different smbd compilation options in one module -*/ -const struct auth_critical_sizes *auth_interface_version(void) -{ - static const struct auth_critical_sizes critical_sizes = { - AUTH_INTERFACE_VERSION, - sizeof(struct auth_operations), - sizeof(struct auth_method_context), - sizeof(struct auth_context), - sizeof(struct auth_usersupplied_info), - sizeof(struct auth_serversupplied_info) - }; - - return &critical_sizes; -} - -_PUBLIC_ NTSTATUS auth_init(void) -{ - static bool initialized = false; - extern NTSTATUS auth_developer_init(void); - extern NTSTATUS auth_winbind_init(void); - extern NTSTATUS auth_anonymous_init(void); - extern NTSTATUS auth_unix_init(void); - extern NTSTATUS auth_sam_init(void); - extern NTSTATUS auth_server_init(void); - - init_module_fn static_init[] = { STATIC_auth_MODULES }; - - if (initialized) return NT_STATUS_OK; - initialized = true; - - run_init_functions(static_init); - - return NT_STATUS_OK; -} - -NTSTATUS server_service_auth_init(void) -{ - return auth_init(); -} diff --git a/source4/auth/auth_anonymous.c b/source4/auth/auth_anonymous.c deleted file mode 100644 index b93c7c2008..0000000000 --- a/source4/auth/auth_anonymous.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - Anonymous Authentification - - Copyright (C) Stefan Metzmacher 2004-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 3 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, see . -*/ - -#include "includes.h" -#include "auth/auth.h" -#include "auth/auth_proto.h" -#include "param/param.h" - -/** - * Return a anonymous logon for anonymous users (username = "") - * - * Typically used as the first module in the auth chain, this allows - * anonymou logons to be dealt with in one place. Non-anonymou logons 'fail' - * and pass onto the next module. - **/ -static NTSTATUS anonymous_want_check(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info) -{ - if (user_info->client.account_name && *user_info->client.account_name) { - return NT_STATUS_NOT_IMPLEMENTED; - } - - return NT_STATUS_OK; -} - -/** - * Return a anonymous logon for anonymous users (username = "") - * - * Typically used as the first module in the auth chain, this allows - * anonymou logons to be dealt with in one place. Non-anonymou logons 'fail' - * and pass onto the next module. - **/ -static NTSTATUS anonymous_check_password(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info, - struct auth_serversupplied_info **_server_info) -{ - return auth_anonymous_server_info(mem_ctx, lp_netbios_name(ctx->auth_ctx->lp_ctx), _server_info); -} - -static const struct auth_operations anonymous_auth_ops = { - .name = "anonymous", - .get_challenge = auth_get_challenge_not_implemented, - .want_check = anonymous_want_check, - .check_password = anonymous_check_password -}; - -_PUBLIC_ NTSTATUS auth_anonymous_init(void) -{ - NTSTATUS ret; - - ret = auth_register(&anonymous_auth_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register 'anonymous' auth backend!\n")); - return ret; - } - - return ret; -} diff --git a/source4/auth/auth_developer.c b/source4/auth/auth_developer.c deleted file mode 100644 index a2c9cbc828..0000000000 --- a/source4/auth/auth_developer.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Generic authentication types - Copyright (C) Andrew Bartlett 2001-2002 - Copyright (C) Jelmer Vernooij 2002 - Copyright (C) Stefan Metzmacher 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 3 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, see . -*/ - -#include "includes.h" -#include "auth/auth.h" -#include "auth/auth_proto.h" -#include "libcli/security/security.h" -#include "librpc/gen_ndr/ndr_samr.h" - -static NTSTATUS name_to_ntstatus_want_check(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info) -{ - return NT_STATUS_OK; -} - -/** - * Return an error based on username - * - * This function allows the testing of obsure errors, as well as the generation - * of NT_STATUS -> DOS error mapping tables. - * - * This module is of no value to end-users. - * - * The password is ignored. - * - * @return An NTSTATUS value based on the username - **/ - -static NTSTATUS name_to_ntstatus_check_password(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info, - struct auth_serversupplied_info **_server_info) -{ - NTSTATUS nt_status; - struct auth_serversupplied_info *server_info; - uint32_t error_num; - const char *user; - - user = user_info->client.account_name; - - if (strncasecmp("NT_STATUS", user, strlen("NT_STATUS")) == 0) { - nt_status = nt_status_string_to_code(user); - } else { - error_num = strtoul(user, NULL, 16); - DEBUG(5,("name_to_ntstatus_check_password: Error for user %s was 0x%08X\n", user, error_num)); - nt_status = NT_STATUS(error_num); - } - NT_STATUS_NOT_OK_RETURN(nt_status); - - server_info = talloc(mem_ctx, struct auth_serversupplied_info); - NT_STATUS_HAVE_NO_MEMORY(server_info); - - server_info->account_sid = dom_sid_parse_talloc(server_info, SID_NT_ANONYMOUS); - NT_STATUS_HAVE_NO_MEMORY(server_info->account_sid); - - /* is this correct? */ - server_info->primary_group_sid = dom_sid_parse_talloc(server_info, SID_BUILTIN_GUESTS); - NT_STATUS_HAVE_NO_MEMORY(server_info->primary_group_sid); - - server_info->n_domain_groups = 0; - server_info->domain_groups = NULL; - - /* annoying, but the Anonymous really does have a session key, - and it is all zeros! */ - server_info->user_session_key = data_blob_talloc(server_info, NULL, 16); - NT_STATUS_HAVE_NO_MEMORY(server_info->user_session_key.data); - - server_info->lm_session_key = data_blob_talloc(server_info, NULL, 16); - NT_STATUS_HAVE_NO_MEMORY(server_info->lm_session_key.data); - - data_blob_clear(&server_info->user_session_key); - data_blob_clear(&server_info->lm_session_key); - - server_info->account_name = talloc_asprintf(server_info, "NAME TO NTSTATUS %s ANONYMOUS LOGON", user); - NT_STATUS_HAVE_NO_MEMORY(server_info->account_name); - - server_info->domain_name = talloc_strdup(server_info, "NT AUTHORITY"); - NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name); - - server_info->full_name = talloc_asprintf(server_info, "NAME TO NTSTATUS %s Anonymous Logon", user); - NT_STATUS_HAVE_NO_MEMORY(server_info->full_name); - - server_info->logon_script = talloc_strdup(server_info, ""); - NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script); - - server_info->profile_path = talloc_strdup(server_info, ""); - NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path); - - server_info->home_directory = talloc_strdup(server_info, ""); - NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory); - - server_info->home_drive = talloc_strdup(server_info, ""); - NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive); - - server_info->last_logon = 0; - server_info->last_logoff = 0; - server_info->acct_expiry = 0; - server_info->last_password_change = 0; - server_info->allow_password_change = 0; - server_info->force_password_change = 0; - - server_info->logon_count = 0; - server_info->bad_password_count = 0; - - server_info->acct_flags = ACB_NORMAL; - - server_info->authenticated = false; - - *_server_info = server_info; - - return nt_status; -} - -static const struct auth_operations name_to_ntstatus_auth_ops = { - .name = "name_to_ntstatus", - .get_challenge = auth_get_challenge_not_implemented, - .want_check = name_to_ntstatus_want_check, - .check_password = name_to_ntstatus_check_password -}; - -/** - * Return a 'fixed' challenge instead of a variable one. - * - * The idea of this function is to make packet snifs consistant - * with a fixed challenge, so as to aid debugging. - * - * This module is of no value to end-users. - * - * This module does not actually authenticate the user, but - * just pretenteds to need a specified challenge. - * This module removes *all* security from the challenge-response system - * - * @return NT_STATUS_UNSUCCESSFUL - **/ -static NTSTATUS fixed_challenge_get_challenge(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, DATA_BLOB *_blob) -{ - DATA_BLOB blob; - const char *challenge = "I am a teapot"; - - blob = data_blob_talloc(mem_ctx, challenge, 8); - NT_STATUS_HAVE_NO_MEMORY(blob.data); - - *_blob = blob; - return NT_STATUS_OK; -} - -static NTSTATUS fixed_challenge_want_check(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info) -{ - /* don't handle any users */ - return NT_STATUS_NOT_IMPLEMENTED; -} - -static NTSTATUS fixed_challenge_check_password(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info, - struct auth_serversupplied_info **_server_info) -{ - /* don't handle any users */ - return NT_STATUS_NO_SUCH_USER; -} - -static const struct auth_operations fixed_challenge_auth_ops = { - .name = "fixed_challenge", - .get_challenge = fixed_challenge_get_challenge, - .want_check = fixed_challenge_want_check, - .check_password = fixed_challenge_check_password -}; - -_PUBLIC_ NTSTATUS auth_developer_init(void) -{ - NTSTATUS ret; - - ret = auth_register(&name_to_ntstatus_auth_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register 'name_to_ntstatus' auth backend!\n")); - return ret; - } - - ret = auth_register(&fixed_challenge_auth_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register 'fixed_challenge' auth backend!\n")); - return ret; - } - - return ret; -} diff --git a/source4/auth/auth_sam.c b/source4/auth/auth_sam.c deleted file mode 100644 index 731e489ba0..0000000000 --- a/source4/auth/auth_sam.c +++ /dev/null @@ -1,448 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Password and authentication handling - Copyright (C) Andrew Bartlett 2001-2004 - Copyright (C) Gerald Carter 2003 - Copyright (C) Stefan Metzmacher 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 3 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, see . -*/ - -#include "includes.h" -#include "librpc/gen_ndr/ndr_netlogon.h" -#include "system/time.h" -#include "lib/ldb/include/ldb.h" -#include "util/util_ldb.h" -#include "auth/auth.h" -#include "auth/auth_proto.h" -#include "auth/auth_sam.h" -#include "dsdb/samdb/samdb.h" -#include "libcli/security/security.h" -#include "libcli/ldap/ldap_ndr.h" -#include "param/param.h" - -extern const char *user_attrs[]; -extern const char *domain_ref_attrs[]; - -/**************************************************************************** - Look for the specified user in the sam, return ldb result structures -****************************************************************************/ - -static NTSTATUS authsam_search_account(TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx, - const char *account_name, - const char *domain_name, - struct ldb_message ***ret_msgs, - struct ldb_message ***ret_msgs_domain_ref) -{ - struct ldb_message **msgs_tmp; - struct ldb_message **msgs; - struct ldb_message **msgs_domain_ref; - struct ldb_dn *partitions_basedn = samdb_partitions_dn(sam_ctx, mem_ctx); - - int ret; - int ret_domain; - - struct ldb_dn *domain_dn = NULL; - - if (domain_name) { - domain_dn = samdb_domain_to_dn(sam_ctx, mem_ctx, domain_name); - if (!domain_dn) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - } - - /* pull the user attributes */ - ret = gendb_search(sam_ctx, mem_ctx, domain_dn, &msgs, user_attrs, - "(&(sAMAccountName=%s)(objectclass=user))", - ldb_binary_encode_string(mem_ctx, account_name)); - if (ret == -1) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - if (ret == 0) { - DEBUG(3,("sam_search_user: Couldn't find user [%s\\%s] in samdb, under %s\n", - domain_name, account_name, ldb_dn_get_linearized(domain_dn))); - return NT_STATUS_NO_SUCH_USER; - } - - if (ret > 1) { - DEBUG(0,("Found %d records matching user [%s]\n", ret, account_name)); - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - if (!domain_dn) { - struct dom_sid *domain_sid; - - domain_sid = samdb_result_sid_prefix(mem_ctx, msgs[0], "objectSid"); - if (!domain_sid) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - /* find the domain's DN */ - ret = gendb_search(sam_ctx, mem_ctx, NULL, &msgs_tmp, NULL, - "(&(objectSid=%s)(objectClass=domain))", - ldap_encode_ndr_dom_sid(mem_ctx, domain_sid)); - if (ret == -1) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - if (ret == 0) { - DEBUG(3,("check_sam_security: Couldn't find domain_sid [%s] in passdb file.\n", - dom_sid_string(mem_ctx, domain_sid))); - return NT_STATUS_NO_SUCH_USER; - } - - if (ret > 1) { - DEBUG(0,("Found %d records matching domain_sid [%s]\n", - ret, dom_sid_string(mem_ctx, domain_sid))); - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - domain_dn = msgs_tmp[0]->dn; - } - - ret_domain = gendb_search(sam_ctx, mem_ctx, partitions_basedn, &msgs_domain_ref, domain_ref_attrs, - "(nCName=%s)", ldb_dn_get_linearized(domain_dn)); - if (ret_domain == -1) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - if (ret_domain == 0) { - DEBUG(3,("check_sam_security: Couldn't find domain [%s] in passdb file.\n", - ldb_dn_get_linearized(msgs_tmp[0]->dn))); - return NT_STATUS_NO_SUCH_USER; - } - - if (ret_domain > 1) { - DEBUG(0,("Found %d records matching domain [%s]\n", - ret_domain, ldb_dn_get_linearized(msgs_tmp[0]->dn))); - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - *ret_msgs = msgs; - *ret_msgs_domain_ref = msgs_domain_ref; - - return NT_STATUS_OK; -} - -/**************************************************************************** - Do a specific test for an smb password being correct, given a smb_password and - the lanman and NT responses. -****************************************************************************/ -static NTSTATUS authsam_password_ok(struct auth_context *auth_context, - TALLOC_CTX *mem_ctx, - uint16_t acct_flags, - const struct samr_Password *lm_pwd, - const struct samr_Password *nt_pwd, - const struct auth_usersupplied_info *user_info, - DATA_BLOB *user_sess_key, - DATA_BLOB *lm_sess_key) -{ - NTSTATUS status; - - if (acct_flags & ACB_PWNOTREQ) { - if (lp_null_passwords(auth_context->lp_ctx)) { - DEBUG(3,("Account for user '%s' has no password and null passwords are allowed.\n", - user_info->mapped.account_name)); - return NT_STATUS_OK; - } else { - DEBUG(3,("Account for user '%s' has no password and null passwords are NOT allowed.\n", - user_info->mapped.account_name)); - return NT_STATUS_LOGON_FAILURE; - } - } - - switch (user_info->password_state) { - case AUTH_PASSWORD_PLAIN: - { - const struct auth_usersupplied_info *user_info_temp; - status = encrypt_user_info(mem_ctx, auth_context, - AUTH_PASSWORD_HASH, - user_info, &user_info_temp); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to convert plaintext password to password HASH: %s\n", nt_errstr(status))); - return status; - } - user_info = user_info_temp; - - /*fall through*/ - } - case AUTH_PASSWORD_HASH: - *lm_sess_key = data_blob(NULL, 0); - *user_sess_key = data_blob(NULL, 0); - status = hash_password_check(mem_ctx, - auth_context->lp_ctx, - user_info->password.hash.lanman, - user_info->password.hash.nt, - user_info->mapped.account_name, - lm_pwd, nt_pwd); - NT_STATUS_NOT_OK_RETURN(status); - break; - - case AUTH_PASSWORD_RESPONSE: - status = ntlm_password_check(mem_ctx, - auth_context->lp_ctx, - user_info->logon_parameters, - &auth_context->challenge.data, - &user_info->password.response.lanman, - &user_info->password.response.nt, - user_info->mapped.account_name, - user_info->client.account_name, - user_info->client.domain_name, - lm_pwd, nt_pwd, - user_sess_key, lm_sess_key); - NT_STATUS_NOT_OK_RETURN(status); - break; - } - - if (user_sess_key && user_sess_key->data) { - talloc_steal(auth_context, user_sess_key->data); - } - if (lm_sess_key && lm_sess_key->data) { - talloc_steal(auth_context, lm_sess_key->data); - } - - return NT_STATUS_OK; -} - - - -static NTSTATUS authsam_authenticate(struct auth_context *auth_context, - TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx, - struct ldb_message **msgs, - struct ldb_message **msgs_domain_ref, - const struct auth_usersupplied_info *user_info, - DATA_BLOB *user_sess_key, DATA_BLOB *lm_sess_key) -{ - struct samr_Password *lm_pwd, *nt_pwd; - NTSTATUS nt_status; - struct ldb_dn *domain_dn = samdb_result_dn(sam_ctx, mem_ctx, msgs_domain_ref[0], "nCName", NULL); - - uint16_t acct_flags = samdb_result_acct_flags(sam_ctx, mem_ctx, msgs[0], domain_dn); - - /* Quit if the account was locked out. */ - if (acct_flags & ACB_AUTOLOCK) { - DEBUG(3,("check_sam_security: Account for user %s was locked out.\n", - user_info->mapped.account_name)); - return NT_STATUS_ACCOUNT_LOCKED_OUT; - } - - /* You can only do an interactive login to normal accounts */ - if (user_info->flags & USER_INFO_INTERACTIVE_LOGON) { - if (!(acct_flags & ACB_NORMAL)) { - return NT_STATUS_NO_SUCH_USER; - } - } - - nt_status = samdb_result_passwords(mem_ctx, msgs[0], &lm_pwd, &nt_pwd); - NT_STATUS_NOT_OK_RETURN(nt_status); - - nt_status = authsam_password_ok(auth_context, mem_ctx, - acct_flags, lm_pwd, nt_pwd, - user_info, user_sess_key, lm_sess_key); - NT_STATUS_NOT_OK_RETURN(nt_status); - - nt_status = authsam_account_ok(mem_ctx, sam_ctx, - user_info->logon_parameters, - msgs[0], - msgs_domain_ref[0], - user_info->workstation_name, - user_info->mapped.account_name); - - return nt_status; -} - - - -static NTSTATUS authsam_check_password_internals(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const char *domain, - const struct auth_usersupplied_info *user_info, - struct auth_serversupplied_info **server_info) -{ - NTSTATUS nt_status; - const char *account_name = user_info->mapped.account_name; - struct ldb_message **msgs; - struct ldb_message **domain_ref_msgs; - struct ldb_context *sam_ctx; - DATA_BLOB user_sess_key, lm_sess_key; - TALLOC_CTX *tmp_ctx; - - if (!account_name || !*account_name) { - /* 'not for me' */ - return NT_STATUS_NOT_IMPLEMENTED; - } - - tmp_ctx = talloc_new(mem_ctx); - if (!tmp_ctx) { - return NT_STATUS_NO_MEMORY; - } - - sam_ctx = samdb_connect(tmp_ctx, ctx->auth_ctx->event_ctx, ctx->auth_ctx->lp_ctx, system_session(mem_ctx, ctx->auth_ctx->lp_ctx)); - if (sam_ctx == NULL) { - talloc_free(tmp_ctx); - return NT_STATUS_INVALID_SYSTEM_SERVICE; - } - - nt_status = authsam_search_account(tmp_ctx, sam_ctx, account_name, domain, &msgs, &domain_ref_msgs); - if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(tmp_ctx); - return nt_status; - } - - nt_status = authsam_authenticate(ctx->auth_ctx, tmp_ctx, sam_ctx, msgs, domain_ref_msgs, user_info, - &user_sess_key, &lm_sess_key); - if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(tmp_ctx); - return nt_status; - } - - nt_status = authsam_make_server_info(tmp_ctx, sam_ctx, lp_netbios_name(ctx->auth_ctx->lp_ctx), - msgs[0], domain_ref_msgs[0], - user_sess_key, lm_sess_key, - server_info); - if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(tmp_ctx); - return nt_status; - } - - talloc_steal(mem_ctx, *server_info); - talloc_free(tmp_ctx); - - return NT_STATUS_OK; -} - -static NTSTATUS authsam_ignoredomain_want_check(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info) -{ - if (!user_info->mapped.account_name || !*user_info->mapped.account_name) { - return NT_STATUS_NOT_IMPLEMENTED; - } - - return NT_STATUS_OK; -} - -static NTSTATUS authsam_ignoredomain_check_password(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info, - struct auth_serversupplied_info **server_info) -{ - return authsam_check_password_internals(ctx, mem_ctx, NULL, user_info, server_info); -} - -/**************************************************************************** -Check SAM security (above) but with a few extra checks. -****************************************************************************/ -static NTSTATUS authsam_want_check(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info) -{ - bool is_local_name, is_my_domain; - - if (!user_info->mapped.account_name || !*user_info->mapped.account_name) { - return NT_STATUS_NOT_IMPLEMENTED; - } - - is_local_name = lp_is_myname(ctx->auth_ctx->lp_ctx, - user_info->mapped.domain_name); - is_my_domain = lp_is_mydomain(ctx->auth_ctx->lp_ctx, - user_info->mapped.domain_name); - - /* check whether or not we service this domain/workgroup name */ - switch (lp_server_role(ctx->auth_ctx->lp_ctx)) { - case ROLE_STANDALONE: - return NT_STATUS_OK; - - case ROLE_DOMAIN_MEMBER: - if (!is_local_name) { - DEBUG(6,("authsam_check_password: %s is not one of my local names (DOMAIN_MEMBER)\n", - user_info->mapped.domain_name)); - return NT_STATUS_NOT_IMPLEMENTED; - } - return NT_STATUS_OK; - - case ROLE_DOMAIN_CONTROLLER: - if (!is_local_name && !is_my_domain) { - DEBUG(6,("authsam_check_password: %s is not one of my local names or domain name (DC)\n", - user_info->mapped.domain_name)); - return NT_STATUS_NOT_IMPLEMENTED; - } - return NT_STATUS_OK; - } - - DEBUG(6,("authsam_check_password: lp_server_role() has an undefined value\n")); - return NT_STATUS_NOT_IMPLEMENTED; -} - -/**************************************************************************** -Check SAM security (above) but with a few extra checks. -****************************************************************************/ -static NTSTATUS authsam_check_password(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info, - struct auth_serversupplied_info **server_info) -{ - const char *domain; - - /* check whether or not we service this domain/workgroup name */ - switch (lp_server_role(ctx->auth_ctx->lp_ctx)) { - case ROLE_STANDALONE: - case ROLE_DOMAIN_MEMBER: - domain = lp_netbios_name(ctx->auth_ctx->lp_ctx); - break; - - case ROLE_DOMAIN_CONTROLLER: - domain = lp_workgroup(ctx->auth_ctx->lp_ctx); - break; - - default: - return NT_STATUS_NO_SUCH_USER; - } - - return authsam_check_password_internals(ctx, mem_ctx, domain, user_info, server_info); -} - -static const struct auth_operations sam_ignoredomain_ops = { - .name = "sam_ignoredomain", - .get_challenge = auth_get_challenge_not_implemented, - .want_check = authsam_ignoredomain_want_check, - .check_password = authsam_ignoredomain_check_password -}; - -static const struct auth_operations sam_ops = { - .name = "sam", - .get_challenge = auth_get_challenge_not_implemented, - .want_check = authsam_want_check, - .check_password = authsam_check_password -}; - -_PUBLIC_ NTSTATUS auth_sam_init(void) -{ - NTSTATUS ret; - - ret = auth_register(&sam_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register 'sam' auth backend!\n")); - return ret; - } - - ret = auth_register(&sam_ignoredomain_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register 'sam_ignoredomain' auth backend!\n")); - return ret; - } - - return ret; -} diff --git a/source4/auth/auth_server.c b/source4/auth/auth_server.c deleted file mode 100644 index be5f84fe39..0000000000 --- a/source4/auth/auth_server.c +++ /dev/null @@ -1,225 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Authenticate by using a remote server - Copyright (C) Andrew Bartlett 2001-2002, 2008 - Copyright (C) Jelmer Vernooij 2002 - Copyright (C) Stefan Metzmacher 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 3 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, see . -*/ - -#include "includes.h" -#include "auth/auth.h" -#include "auth/auth_proto.h" -#include "auth/credentials/credentials.h" -#include "libcli/security/security.h" -#include "librpc/gen_ndr/ndr_samr.h" -#include "libcli/smb_composite/smb_composite.h" -#include "param/param.h" -#include "libcli/resolve/resolve.h" - -/* This version of 'security=server' rewirtten from scratch for Samba4 - * libraries in 2008 */ - - -static NTSTATUS server_want_check(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info) -{ - return NT_STATUS_OK; -} -/** - * The challenge from the target server, when operating in security=server - **/ -static NTSTATUS server_get_challenge(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, DATA_BLOB *_blob) -{ - struct smb_composite_connect io; - struct smbcli_options smb_options; - const char **host_list; - NTSTATUS status; - - /* Make a connection to the target server, found by 'password server' in smb.conf */ - - lp_smbcli_options(ctx->auth_ctx->lp_ctx, &smb_options); - - /* Make a negprot, WITHOUT SPNEGO, so we get a challenge nice an easy */ - io.in.options.use_spnego = false; - - /* Hope we don't get * (the default), as this won't work... */ - host_list = lp_passwordserver(ctx->auth_ctx->lp_ctx); - if (!host_list) { - return NT_STATUS_INTERNAL_ERROR; - } - io.in.dest_host = host_list[0]; - if (strequal(io.in.dest_host, "*")) { - return NT_STATUS_INTERNAL_ERROR; - } - io.in.dest_ports = lp_smb_ports(ctx->auth_ctx->lp_ctx); - - io.in.called_name = strupper_talloc(mem_ctx, io.in.dest_host); - - /* We don't want to get as far as the session setup */ - io.in.credentials = NULL; - io.in.service = NULL; - - io.in.workgroup = ""; /* only used with SPNEGO, disabled above */ - - io.in.options = smb_options; - - status = smb_composite_connect(&io, mem_ctx, lp_resolve_context(ctx->auth_ctx->lp_ctx), - ctx->auth_ctx->event_ctx); - if (!NT_STATUS_IS_OK(status)) { - *_blob = io.out.tree->session->transport->negotiate.secblob; - ctx->private_data = talloc_steal(ctx, io.out.tree->session); - } - return NT_STATUS_OK; -} - -/** - * Return an error based on username - * - * This function allows the testing of obsure errors, as well as the generation - * of NT_STATUS -> DOS error mapping tables. - * - * This module is of no value to end-users. - * - * The password is ignored. - * - * @return An NTSTATUS value based on the username - **/ - -static NTSTATUS server_check_password(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info, - struct auth_serversupplied_info **_server_info) -{ - NTSTATUS nt_status; - struct auth_serversupplied_info *server_info; - struct cli_credentials *creds; - const char *user; - struct smb_composite_sesssetup session_setup; - - struct smbcli_session *session = talloc_get_type(ctx->private_data, struct smbcli_session); - - creds = cli_credentials_init(mem_ctx); - - NT_STATUS_HAVE_NO_MEMORY(creds); - - cli_credentials_set_username(creds, user_info->client.account_name, CRED_SPECIFIED); - cli_credentials_set_domain(creds, user_info->client.domain_name, CRED_SPECIFIED); - - switch (user_info->password_state) { - case AUTH_PASSWORD_PLAIN: - cli_credentials_set_password(creds, user_info->password.plaintext, - CRED_SPECIFIED); - break; - case AUTH_PASSWORD_HASH: - cli_credentials_set_nt_hash(creds, user_info->password.hash.nt, - CRED_SPECIFIED); - break; - - case AUTH_PASSWORD_RESPONSE: - cli_credentials_set_ntlm_response(creds, &user_info->password.response.lanman, &user_info->password.response.nt, CRED_SPECIFIED); - break; - } - - session_setup.in.sesskey = session->transport->negotiate.sesskey; - session_setup.in.capabilities = session->transport->negotiate.capabilities; - - session_setup.in.credentials = creds; - session_setup.in.workgroup = ""; /* Only used with SPNEGO, which we are not doing */ - - /* Check password with remove server - this should be async some day */ - nt_status = smb_composite_sesssetup(session, &session_setup); - - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - server_info = talloc(mem_ctx, struct auth_serversupplied_info); - NT_STATUS_HAVE_NO_MEMORY(server_info); - - server_info->account_sid = dom_sid_parse_talloc(server_info, SID_NT_ANONYMOUS); - NT_STATUS_HAVE_NO_MEMORY(server_info->account_sid); - - /* is this correct? */ - server_info->primary_group_sid = dom_sid_parse_talloc(server_info, SID_BUILTIN_GUESTS); - NT_STATUS_HAVE_NO_MEMORY(server_info->primary_group_sid); - - server_info->n_domain_groups = 0; - server_info->domain_groups = NULL; - - /* annoying, but the Anonymous really does have a session key, - and it is all zeros! */ - server_info->user_session_key = data_blob(NULL, 0); - server_info->lm_session_key = data_blob(NULL, 0); - - server_info->account_name = talloc_strdup(server_info, user_info->client.account_name); - NT_STATUS_HAVE_NO_MEMORY(server_info->account_name); - - server_info->domain_name = talloc_strdup(server_info, user_info->client.domain_name); - NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name); - - server_info->full_name = NULL; - - server_info->logon_script = talloc_strdup(server_info, ""); - NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script); - - server_info->profile_path = talloc_strdup(server_info, ""); - NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path); - - server_info->home_directory = talloc_strdup(server_info, ""); - NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory); - - server_info->home_drive = talloc_strdup(server_info, ""); - NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive); - - server_info->last_logon = 0; - server_info->last_logoff = 0; - server_info->acct_expiry = 0; - server_info->last_password_change = 0; - server_info->allow_password_change = 0; - server_info->force_password_change = 0; - - server_info->logon_count = 0; - server_info->bad_password_count = 0; - - server_info->acct_flags = ACB_NORMAL; - - server_info->authenticated = false; - - *_server_info = server_info; - - return nt_status; -} - -static const struct auth_operations server_auth_ops = { - .name = "server", - .get_challenge = server_get_challenge, - .want_check = server_want_check, - .check_password = server_check_password -}; - -_PUBLIC_ NTSTATUS auth_server_init(void) -{ - NTSTATUS ret; - - ret = auth_register(&server_auth_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register 'server' auth backend!\n")); - return ret; - } - - return ret; -} diff --git a/source4/auth/auth_simple.c b/source4/auth/auth_simple.c deleted file mode 100644 index e7039c3657..0000000000 --- a/source4/auth/auth_simple.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - auth functions - - Copyright (C) Simo Sorce 2005 - Copyright (C) Andrew Tridgell 2005 - Copyright (C) Andrew Bartlett 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 3 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, see . -*/ - -#include "includes.h" -#include "auth/auth.h" -#include "lib/events/events.h" -#include "param/param.h" -#include "auth/session_proto.h" - -/* - It's allowed to pass NULL as session_info, - when the caller doesn't need a session_info -*/ -_PUBLIC_ NTSTATUS authenticate_username_pw(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct messaging_context *msg, - struct loadparm_context *lp_ctx, - const char *nt4_domain, - const char *nt4_username, - const char *password, - struct auth_session_info **session_info) -{ - struct auth_context *auth_context; - struct auth_usersupplied_info *user_info; - struct auth_serversupplied_info *server_info; - NTSTATUS nt_status; - TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); - - if (!tmp_ctx) { - return NT_STATUS_NO_MEMORY; - } - - nt_status = auth_context_create(tmp_ctx, - ev, msg, - lp_ctx, - &auth_context); - if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(tmp_ctx); - return nt_status; - } - - user_info = talloc(tmp_ctx, struct auth_usersupplied_info); - if (!user_info) { - talloc_free(tmp_ctx); - return NT_STATUS_NO_MEMORY; - } - - user_info->mapped_state = true; - user_info->client.account_name = nt4_username; - user_info->mapped.account_name = nt4_username; - user_info->client.domain_name = nt4_domain; - user_info->mapped.domain_name = nt4_domain; - - user_info->workstation_name = NULL; - - user_info->remote_host = NULL; - - user_info->password_state = AUTH_PASSWORD_PLAIN; - user_info->password.plaintext = talloc_strdup(user_info, password); - - user_info->flags = USER_INFO_CASE_INSENSITIVE_USERNAME | - USER_INFO_DONT_CHECK_UNIX_ACCOUNT; - - user_info->logon_parameters = 0; - - nt_status = auth_check_password(auth_context, tmp_ctx, user_info, &server_info); - if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(tmp_ctx); - return nt_status; - } - - if (session_info) { - nt_status = auth_generate_session_info(tmp_ctx, ev, lp_ctx, server_info, session_info); - - if (NT_STATUS_IS_OK(nt_status)) { - talloc_steal(mem_ctx, *session_info); - } - } - - talloc_free(tmp_ctx); - return nt_status; -} - diff --git a/source4/auth/auth_unix.c b/source4/auth/auth_unix.c deleted file mode 100644 index a417107025..0000000000 --- a/source4/auth/auth_unix.c +++ /dev/null @@ -1,844 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Password and authentication handling - Copyright (C) Andrew Bartlett 2001 - Copyright (C) Jeremy Allison 2001 - Copyright (C) Simo Sorce 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 3 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, see . -*/ - -#include "includes.h" -#include "auth/auth.h" -#include "auth/auth_proto.h" -#include "system/passwd.h" /* needed by some systems for struct passwd */ -#include "lib/socket/socket.h" -#include "auth/pam_errors.h" -#include "param/param.h" - -/* TODO: look at how to best fill in parms retrieveing a struct passwd info - * except in case USER_INFO_DONT_CHECK_UNIX_ACCOUNT is set - */ -static NTSTATUS authunix_make_server_info(TALLOC_CTX *mem_ctx, - const char *netbios_name, - const struct auth_usersupplied_info *user_info, - struct passwd *pwd, - struct auth_serversupplied_info **_server_info) -{ - struct auth_serversupplied_info *server_info; - NTSTATUS status; - - /* This is a real, real hack */ - if (pwd->pw_uid == 0) { - status = auth_system_server_info(mem_ctx, netbios_name, &server_info); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - server_info->account_name = talloc_steal(server_info, pwd->pw_name); - NT_STATUS_HAVE_NO_MEMORY(server_info->account_name); - - server_info->domain_name = talloc_strdup(server_info, "unix"); - NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name); - } else { - server_info = talloc(mem_ctx, struct auth_serversupplied_info); - NT_STATUS_HAVE_NO_MEMORY(server_info); - - server_info->authenticated = true; - - server_info->account_name = talloc_steal(server_info, pwd->pw_name); - NT_STATUS_HAVE_NO_MEMORY(server_info->account_name); - - server_info->domain_name = talloc_strdup(server_info, "unix"); - NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name); - - /* This isn't in any way correct.. */ - server_info->account_sid = NULL; - server_info->primary_group_sid = NULL; - server_info->n_domain_groups = 0; - server_info->domain_groups = NULL; - } - server_info->user_session_key = data_blob(NULL,0); - server_info->lm_session_key = data_blob(NULL,0); - - server_info->full_name = talloc_steal(server_info, pwd->pw_gecos); - NT_STATUS_HAVE_NO_MEMORY(server_info->full_name); - server_info->logon_script = talloc_strdup(server_info, ""); - NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script); - server_info->profile_path = talloc_strdup(server_info, ""); - NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path); - server_info->home_directory = talloc_strdup(server_info, ""); - NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory); - server_info->home_drive = talloc_strdup(server_info, ""); - NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive); - - server_info->last_logon = 0; - server_info->last_logoff = 0; - server_info->acct_expiry = 0; - server_info->last_password_change = 0; - server_info->allow_password_change = 0; - server_info->force_password_change = 0; - server_info->logon_count = 0; - server_info->bad_password_count = 0; - server_info->acct_flags = 0; - - *_server_info = server_info; - - return NT_STATUS_OK; -} - -static NTSTATUS talloc_getpwnam(TALLOC_CTX *ctx, const char *username, struct passwd **pws) -{ - struct passwd *ret; - struct passwd *from; - - *pws = NULL; - - ret = talloc(ctx, struct passwd); - NT_STATUS_HAVE_NO_MEMORY(ret); - - from = getpwnam(username); - if (!from) { - return NT_STATUS_NO_SUCH_USER; - } - - ret->pw_name = talloc_strdup(ctx, from->pw_name); - NT_STATUS_HAVE_NO_MEMORY(ret->pw_name); - - ret->pw_passwd = talloc_strdup(ctx, from->pw_passwd); - NT_STATUS_HAVE_NO_MEMORY(ret->pw_passwd); - - ret->pw_uid = from->pw_uid; - ret->pw_gid = from->pw_gid; - ret->pw_gecos = talloc_strdup(ctx, from->pw_gecos); - NT_STATUS_HAVE_NO_MEMORY(ret->pw_gecos); - - ret->pw_dir = talloc_strdup(ctx, from->pw_dir); - NT_STATUS_HAVE_NO_MEMORY(ret->pw_dir); - - ret->pw_shell = talloc_strdup(ctx, from->pw_shell); - NT_STATUS_HAVE_NO_MEMORY(ret->pw_shell); - - *pws = ret; - - return NT_STATUS_OK; -} - - -#ifdef HAVE_SECURITY_PAM_APPL_H -#include - -struct smb_pam_user_info { - const char *account_name; - const char *plaintext_password; -}; - -#define COPY_STRING(s) (s) ? strdup(s) : NULL - -/* - * Check user password - * Currently it uses PAM only and fails on systems without PAM - * Samba3 code located in pass_check.c is to ugly to be used directly it will - * need major rework that's why pass_check.c is still there. -*/ - -static int smb_pam_conv(int num_msg, const struct pam_message **msg, - struct pam_response **reply, void *appdata_ptr) -{ - struct smb_pam_user_info *info = (struct smb_pam_user_info *)appdata_ptr; - int num; - - if (num_msg <= 0) { - *reply = NULL; - return PAM_CONV_ERR; - } - - /* - * Apparantly HPUX has a buggy PAM that doesn't support the - * data pointer. Fail if this is the case. JRA. - */ - - if (info == NULL) { - *reply = NULL; - return PAM_CONV_ERR; - } - - /* - * PAM frees memory in reply messages by itself - * so use malloc instead of talloc here. - */ - *reply = malloc_array_p(struct pam_response, num_msg); - if (*reply == NULL) { - return PAM_CONV_ERR; - } - - for (num = 0; num < num_msg; num++) { - switch (msg[num]->msg_style) { - case PAM_PROMPT_ECHO_ON: - (*reply)[num].resp_retcode = PAM_SUCCESS; - (*reply)[num].resp = COPY_STRING(info->account_name); - break; - - case PAM_PROMPT_ECHO_OFF: - (*reply)[num].resp_retcode = PAM_SUCCESS; - (*reply)[num].resp = COPY_STRING(info->plaintext_password); - break; - - case PAM_TEXT_INFO: - (*reply)[num].resp_retcode = PAM_SUCCESS; - (*reply)[num].resp = NULL; - DEBUG(4,("PAM Info message in conversation function: %s\n", (msg[num]->msg))); - break; - - case PAM_ERROR_MSG: - (*reply)[num].resp_retcode = PAM_SUCCESS; - (*reply)[num].resp = NULL; - DEBUG(4,("PAM Error message in conversation function: %s\n", (msg[num]->msg))); - break; - - default: - while (num > 0) { - SAFE_FREE((*reply)[num-1].resp); - num--; - } - SAFE_FREE(*reply); - *reply = NULL; - DEBUG(1,("Error: PAM subsystme sent an UNKNOWN message type to the conversation function!\n")); - return PAM_CONV_ERR; - } - } - - return PAM_SUCCESS; -} - -/* - * Start PAM authentication for specified account - */ - -static NTSTATUS smb_pam_start(pam_handle_t **pamh, const char *account_name, const char *remote_host, struct pam_conv *pconv) -{ - int pam_error; - - if (account_name == NULL || remote_host == NULL) { - return NT_STATUS_INVALID_PARAMETER; - } - - DEBUG(4,("smb_pam_start: PAM: Init user: %s\n", account_name)); - - pam_error = pam_start("samba", account_name, pconv, pamh); - if (pam_error != PAM_SUCCESS) { - /* no valid pamh here, can we reliably call pam_strerror ? */ - DEBUG(4,("smb_pam_start: pam_start failed!\n")); - return NT_STATUS_UNSUCCESSFUL; - } - -#ifdef PAM_RHOST - DEBUG(4,("smb_pam_start: PAM: setting rhost to: %s\n", remote_host)); - pam_error = pam_set_item(*pamh, PAM_RHOST, remote_host); - if (pam_error != PAM_SUCCESS) { - NTSTATUS nt_status; - - DEBUG(4,("smb_pam_start: setting rhost failed with error: %s\n", - pam_strerror(*pamh, pam_error))); - nt_status = pam_to_nt_status(pam_error); - - pam_error = pam_end(*pamh, 0); - if (pam_error != PAM_SUCCESS) { - /* no vaild pamh here, can we reliably call pam_strerror ? */ - DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n", - pam_error)); - return pam_to_nt_status(pam_error); - } - return nt_status; - } -#endif -#ifdef PAM_TTY - DEBUG(4,("smb_pam_start: PAM: setting tty\n")); - pam_error = pam_set_item(*pamh, PAM_TTY, "samba"); - if (pam_error != PAM_SUCCESS) { - NTSTATUS nt_status; - - DEBUG(4,("smb_pam_start: setting tty failed with error: %s\n", - pam_strerror(*pamh, pam_error))); - nt_status = pam_to_nt_status(pam_error); - - pam_error = pam_end(*pamh, 0); - if (pam_error != PAM_SUCCESS) { - /* no vaild pamh here, can we reliably call pam_strerror ? */ - DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n", - pam_error)); - return pam_to_nt_status(pam_error); - } - return nt_status; - } -#endif - DEBUG(4,("smb_pam_start: PAM: Init passed for user: %s\n", account_name)); - - return NT_STATUS_OK; -} - -static NTSTATUS smb_pam_end(pam_handle_t *pamh) -{ - int pam_error; - - if (pamh != NULL) { - pam_error = pam_end(pamh, 0); - if (pam_error != PAM_SUCCESS) { - /* no vaild pamh here, can we reliably call pam_strerror ? */ - DEBUG(4,("smb_pam_end: clean up failed, pam_end gave error %d.\n", - pam_error)); - return pam_to_nt_status(pam_error); - } - return NT_STATUS_OK; - } - - DEBUG(2,("smb_pam_end: pamh is NULL, PAM not initialized ?\n")); - return NT_STATUS_UNSUCCESSFUL; -} - -/* - * PAM Authentication Handler - */ -static NTSTATUS smb_pam_auth(pam_handle_t *pamh, bool allow_null_passwords, const char *user) -{ - int pam_error; - - /* - * To enable debugging set in /etc/pam.d/samba: - * auth required /lib/security/pam_pwdb.so nullok shadow audit - */ - - DEBUG(4,("smb_pam_auth: PAM: Authenticate User: %s\n", user)); - - pam_error = pam_authenticate(pamh, PAM_SILENT | allow_null_passwords ? 0 : PAM_DISALLOW_NULL_AUTHTOK); - switch( pam_error ){ - case PAM_AUTH_ERR: - DEBUG(2, ("smb_pam_auth: PAM: Authentication Error for user %s\n", user)); - break; - case PAM_CRED_INSUFFICIENT: - DEBUG(2, ("smb_pam_auth: PAM: Insufficient Credentials for user %s\n", user)); - break; - case PAM_AUTHINFO_UNAVAIL: - DEBUG(2, ("smb_pam_auth: PAM: Authentication Information Unavailable for user %s\n", user)); - break; - case PAM_USER_UNKNOWN: - DEBUG(2, ("smb_pam_auth: PAM: Username %s NOT known to Authentication system\n", user)); - break; - case PAM_MAXTRIES: - DEBUG(2, ("smb_pam_auth: PAM: One or more authentication modules reports user limit for user %s exceeeded\n", user)); - break; - case PAM_ABORT: - DEBUG(0, ("smb_pam_auth: PAM: One or more PAM modules failed to load for user %s\n", user)); - break; - case PAM_SUCCESS: - DEBUG(4, ("smb_pam_auth: PAM: User %s Authenticated OK\n", user)); - break; - default: - DEBUG(0, ("smb_pam_auth: PAM: UNKNOWN ERROR while authenticating user %s\n", user)); - break; - } - - return pam_to_nt_status(pam_error); -} - -/* - * PAM Account Handler - */ -static NTSTATUS smb_pam_account(pam_handle_t *pamh, const char * user) -{ - int pam_error; - - DEBUG(4,("smb_pam_account: PAM: Account Management for User: %s\n", user)); - - pam_error = pam_acct_mgmt(pamh, PAM_SILENT); /* Is user account enabled? */ - switch( pam_error ) { - case PAM_AUTHTOK_EXPIRED: - DEBUG(2, ("smb_pam_account: PAM: User %s is valid but password is expired\n", user)); - break; - case PAM_ACCT_EXPIRED: - DEBUG(2, ("smb_pam_account: PAM: User %s no longer permitted to access system\n", user)); - break; - case PAM_AUTH_ERR: - DEBUG(2, ("smb_pam_account: PAM: There was an authentication error for user %s\n", user)); - break; - case PAM_PERM_DENIED: - DEBUG(0, ("smb_pam_account: PAM: User %s is NOT permitted to access system at this time\n", user)); - break; - case PAM_USER_UNKNOWN: - DEBUG(0, ("smb_pam_account: PAM: User \"%s\" is NOT known to account management\n", user)); - break; - case PAM_SUCCESS: - DEBUG(4, ("smb_pam_account: PAM: Account OK for User: %s\n", user)); - break; - default: - DEBUG(0, ("smb_pam_account: PAM: UNKNOWN PAM ERROR (%d) during Account Management for User: %s\n", pam_error, user)); - break; - } - - return pam_to_nt_status(pam_error); -} - -/* - * PAM Credential Setting - */ - -static NTSTATUS smb_pam_setcred(pam_handle_t *pamh, const char * user) -{ - int pam_error; - - /* - * This will allow samba to aquire a kerberos token. And, when - * exporting an AFS cell, be able to /write/ to this cell. - */ - - DEBUG(4,("PAM: Account Management SetCredentials for User: %s\n", user)); - - pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED|PAM_SILENT)); - switch( pam_error ) { - case PAM_CRED_UNAVAIL: - DEBUG(0, ("smb_pam_setcred: PAM: Credentials not found for user:%s\n", user )); - break; - case PAM_CRED_EXPIRED: - DEBUG(0, ("smb_pam_setcred: PAM: Credentials for user: \"%s\" EXPIRED!\n", user )); - break; - case PAM_USER_UNKNOWN: - DEBUG(0, ("smb_pam_setcred: PAM: User: \"%s\" is NOT known so can not set credentials!\n", user )); - break; - case PAM_CRED_ERR: - DEBUG(0, ("smb_pam_setcred: PAM: Unknown setcredentials error - unable to set credentials for %s\n", user )); - break; - case PAM_SUCCESS: - DEBUG(4, ("smb_pam_setcred: PAM: SetCredentials OK for User: %s\n", user)); - break; - default: - DEBUG(0, ("smb_pam_setcred: PAM: UNKNOWN PAM ERROR (%d) during SetCredentials for User: %s\n", pam_error, user)); - break; - } - - return pam_to_nt_status(pam_error); -} - -static NTSTATUS check_unix_password(TALLOC_CTX *ctx, struct loadparm_context *lp_ctx, - const struct auth_usersupplied_info *user_info, struct passwd **pws) -{ - struct smb_pam_user_info *info; - struct pam_conv *pamconv; - pam_handle_t *pamh; - NTSTATUS nt_status; - - info = talloc(ctx, struct smb_pam_user_info); - if (info == NULL) { - return NT_STATUS_NO_MEMORY; - } - - info->account_name = user_info->mapped.account_name; - info->plaintext_password = user_info->password.plaintext; - - pamconv = talloc(ctx, struct pam_conv); - if (pamconv == NULL) { - return NT_STATUS_NO_MEMORY; - } - - pamconv->conv = smb_pam_conv; - pamconv->appdata_ptr = (void *)info; - - /* TODO: - * check for user_info->flags & USER_INFO_CASE_INSENSITIVE_USERNAME - * if true set up a crack name routine. - */ - - nt_status = smb_pam_start(&pamh, user_info->mapped.account_name, user_info->remote_host ? user_info->remote_host->addr : NULL, pamconv); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - nt_status = smb_pam_auth(pamh, lp_null_passwords(lp_ctx), user_info->mapped.account_name); - if (!NT_STATUS_IS_OK(nt_status)) { - smb_pam_end(pamh); - return nt_status; - } - - if ( ! (user_info->flags & USER_INFO_DONT_CHECK_UNIX_ACCOUNT)) { - - nt_status = smb_pam_account(pamh, user_info->mapped.account_name); - if (!NT_STATUS_IS_OK(nt_status)) { - smb_pam_end(pamh); - return nt_status; - } - - nt_status = smb_pam_setcred(pamh, user_info->mapped.account_name); - if (!NT_STATUS_IS_OK(nt_status)) { - smb_pam_end(pamh); - return nt_status; - } - } - - smb_pam_end(pamh); - - nt_status = talloc_getpwnam(ctx, user_info->mapped.account_name, pws); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - return NT_STATUS_OK; -} - -#else - -/**************************************************************************** -core of password checking routine -****************************************************************************/ -static NTSTATUS password_check(const char *username, const char *password, - const char *crypted, const char *salt) -{ - bool ret; - -#ifdef WITH_AFS - if (afs_auth(username, password)) - return NT_STATUS_OK; -#endif /* WITH_AFS */ - -#ifdef WITH_DFS - if (dfs_auth(username, password)) - return NT_STATUS_OK; -#endif /* WITH_DFS */ - -#ifdef OSF1_ENH_SEC - - ret = (strcmp(osf1_bigcrypt(password, salt), crypted) == 0); - - if (!ret) { - DEBUG(2, - ("OSF1_ENH_SEC failed. Trying normal crypt.\n")); - ret = (strcmp((char *)crypt(password, salt), crypted) == 0); - } - if (ret) { - return NT_STATUS_OK; - } else { - return NT_STATUS_WRONG_PASSWORD; - } - -#endif /* OSF1_ENH_SEC */ - -#ifdef ULTRIX_AUTH - ret = (strcmp((char *)crypt16(password, salt), crypted) == 0); - if (ret) { - return NT_STATUS_OK; - } else { - return NT_STATUS_WRONG_PASSWORD; - } - -#endif /* ULTRIX_AUTH */ - -#ifdef LINUX_BIGCRYPT - ret = (linux_bigcrypt(password, salt, crypted)); - if (ret) { - return NT_STATUS_OK; - } else { - return NT_STATUS_WRONG_PASSWORD; - } -#endif /* LINUX_BIGCRYPT */ - -#if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS) - - /* - * Some systems have bigcrypt in the C library but might not - * actually use it for the password hashes (HPUX 10.20) is - * a noteable example. So we try bigcrypt first, followed - * by crypt. - */ - - if (strcmp(bigcrypt(password, salt), crypted) == 0) - return NT_STATUS_OK; - else - ret = (strcmp((char *)crypt(password, salt), crypted) == 0); - if (ret) { - return NT_STATUS_OK; - } else { - return NT_STATUS_WRONG_PASSWORD; - } -#else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */ - -#ifdef HAVE_BIGCRYPT - ret = (strcmp(bigcrypt(password, salt), crypted) == 0); - if (ret) { - return NT_STATUS_OK; - } else { - return NT_STATUS_WRONG_PASSWORD; - } -#endif /* HAVE_BIGCRYPT */ - -#ifndef HAVE_CRYPT - DEBUG(1, ("Warning - no crypt available\n")); - return NT_STATUS_LOGON_FAILURE; -#else /* HAVE_CRYPT */ - ret = (strcmp((char *)crypt(password, salt), crypted) == 0); - if (ret) { - return NT_STATUS_OK; - } else { - return NT_STATUS_WRONG_PASSWORD; - } -#endif /* HAVE_CRYPT */ -#endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */ -} - -static NTSTATUS check_unix_password(TALLOC_CTX *ctx, struct loadparm_context *lp_ctx, - const struct auth_usersupplied_info *user_info, struct passwd **ret_passwd) -{ - char *username; - char *password; - char *pwcopy; - char *salt; - char *crypted; - struct passwd *pws; - NTSTATUS nt_status; - int level = lp_passwordlevel(lp_ctx); - - *ret_passwd = NULL; - - username = talloc_strdup(ctx, user_info->mapped.account_name); - password = talloc_strdup(ctx, user_info->password.plaintext); - - nt_status = talloc_getpwnam(ctx, username, &pws); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - crypted = pws->pw_passwd; - salt = pws->pw_passwd; - -#ifdef HAVE_GETSPNAM - { - struct spwd *spass; - - /* many shadow systems require you to be root to get - the password, in most cases this should already be - the case when this function is called, except - perhaps for IPC password changing requests */ - - spass = getspnam(pws->pw_name); - if (spass && spass->sp_pwdp) { - crypted = talloc_strdup(ctx, spass->sp_pwdp); - NT_STATUS_HAVE_NO_MEMORY(crypted); - salt = talloc_strdup(ctx, spass->sp_pwdp); - NT_STATUS_HAVE_NO_MEMORY(salt); - } - } -#elif defined(IA_UINFO) - { - char *ia_password; - /* Need to get password with SVR4.2's ia_ functions - instead of get{sp,pw}ent functions. Required by - UnixWare 2.x, tested on version - 2.1. (tangent@cyberport.com) */ - uinfo_t uinfo; - if (ia_openinfo(pws->pw_name, &uinfo) != -1) { - ia_get_logpwd(uinfo, &ia_password); - crypted = talloc_strdup(ctx, ia_password); - NT_STATUS_HAVE_NO_MEMORY(crypted); - } - } -#endif - -#ifdef HAVE_GETPRPWNAM - { - struct pr_passwd *pr_pw = getprpwnam(pws->pw_name); - if (pr_pw && pr_pw->ufld.fd_encrypt) { - crypted = talloc_strdup(ctx, pr_pw->ufld.fd_encrypt); - NT_STATUS_HAVE_NO_MEMORY(crypted); - } - } -#endif - -#ifdef HAVE_GETPWANAM - { - struct passwd_adjunct *pwret; - pwret = getpwanam(s); - if (pwret && pwret->pwa_passwd) { - crypted = talloc_strdup(ctx, pwret->pwa_passwd); - NT_STATUS_HAVE_NO_MEMORY(crypted); - } - } -#endif - -#ifdef OSF1_ENH_SEC - { - struct pr_passwd *mypasswd; - DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n", username)); - mypasswd = getprpwnam(username); - if (mypasswd) { - username = talloc_strdup(ctx, mypasswd->ufld.fd_name); - NT_STATUS_HAVE_NO_MEMORY(username); - crypted = talloc_strdup(ctx, mypasswd->ufld.fd_encrypt); - NT_STATUS_HAVE_NO_MEMORY(crypted); - } else { - DEBUG(5,("OSF1_ENH_SEC: No entry for user %s in protected database !\n", username)); - } - } -#endif - -#ifdef ULTRIX_AUTH - { - AUTHORIZATION *ap = getauthuid(pws->pw_uid); - if (ap) { - crypted = talloc_strdup(ctx, ap->a_password); - endauthent(); - NT_STATUS_HAVE_NO_MEMORY(crypted); - } - } -#endif - -#if defined(HAVE_TRUNCATED_SALT) - /* crypt on some platforms (HPUX in particular) - won't work with more than 2 salt characters. */ - salt[2] = 0; -#endif - - if (crypted[0] == '\0') { - if (!lp_null_passwords(lp_ctx)) { - DEBUG(2, ("Disallowing %s with null password\n", username)); - return NT_STATUS_LOGON_FAILURE; - } - if (password == NULL) { - DEBUG(3, ("Allowing access to %s with null password\n", username)); - *ret_passwd = pws; - return NT_STATUS_OK; - } - } - - /* try it as it came to us */ - nt_status = password_check(username, password, crypted, salt); - if (NT_STATUS_IS_OK(nt_status)) { - *ret_passwd = pws; - return nt_status; - } - else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) { - /* No point continuing if its not the password thats to blame (ie PAM disabled). */ - return nt_status; - } - - if ( user_info->flags | USER_INFO_CASE_INSENSITIVE_PASSWORD) { - return nt_status; - } - - /* if the password was given to us with mixed case then we don't - * need to proceed as we know it hasn't been case modified by the - * client */ - if (strhasupper(password) && strhaslower(password)) { - return nt_status; - } - - /* make a copy of it */ - pwcopy = talloc_strdup(ctx, password); - if (!pwcopy) - return NT_STATUS_NO_MEMORY; - - /* try all lowercase if it's currently all uppercase */ - if (strhasupper(pwcopy)) { - strlower(pwcopy); - nt_status = password_check(username, pwcopy, crypted, salt); - if NT_STATUS_IS_OK(nt_status) { - *ret_passwd = pws; - return nt_status; - } - } - - /* give up? */ - if (level < 1) { - return NT_STATUS_WRONG_PASSWORD; - } - - /* last chance - all combinations of up to level chars upper! */ - strlower(pwcopy); - -#if 0 - if (NT_STATUS_IS_OK(nt_status = string_combinations(pwcopy, password_check, level))) { - *ret_passwd = pws; - return nt_status; - } -#endif - return NT_STATUS_WRONG_PASSWORD; -} - -#endif - -/** Check a plaintext username/password - * - **/ - -static NTSTATUS authunix_want_check(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info) -{ - if (!user_info->mapped.account_name || !*user_info->mapped.account_name) { - return NT_STATUS_NOT_IMPLEMENTED; - } - - return NT_STATUS_OK; -} - -static NTSTATUS authunix_check_password(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info, - struct auth_serversupplied_info **server_info) -{ - TALLOC_CTX *check_ctx; - NTSTATUS nt_status; - struct passwd *pwd; - - if (user_info->password_state != AUTH_PASSWORD_PLAIN) { - return NT_STATUS_INVALID_PARAMETER; - } - - check_ctx = talloc_named_const(mem_ctx, 0, "check_unix_password"); - if (check_ctx == NULL) { - return NT_STATUS_NO_MEMORY; - } - - nt_status = check_unix_password(check_ctx, ctx->auth_ctx->lp_ctx, user_info, &pwd); - if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(check_ctx); - return nt_status; - } - - nt_status = authunix_make_server_info(mem_ctx, lp_netbios_name(ctx->auth_ctx->lp_ctx), - user_info, pwd, server_info); - if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(check_ctx); - return nt_status; - } - - talloc_free(check_ctx); - return NT_STATUS_OK; -} - -static const struct auth_operations unix_ops = { - .name = "unix", - .get_challenge = auth_get_challenge_not_implemented, - .want_check = authunix_want_check, - .check_password = authunix_check_password -}; - -_PUBLIC_ NTSTATUS auth_unix_init(void) -{ - NTSTATUS ret; - - ret = auth_register(&unix_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register unix auth backend!\n")); - return ret; - } - - return ret; -} diff --git a/source4/auth/auth_util.c b/source4/auth/auth_util.c deleted file mode 100644 index 1d86b858cf..0000000000 --- a/source4/auth/auth_util.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Authentication utility functions - Copyright (C) Andrew Tridgell 1992-1998 - Copyright (C) Andrew Bartlett 2001 - Copyright (C) Jeremy Allison 2000-2001 - Copyright (C) Rafal Szczesniak 2002 - Copyright (C) Stefan Metzmacher 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 3 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, see . -*/ - -#include "includes.h" -#include "auth/auth.h" -#include "libcli/security/security.h" -#include "libcli/auth/libcli_auth.h" -#include "dsdb/samdb/samdb.h" -#include "auth/credentials/credentials.h" -#include "param/param.h" - -/* this default function can be used by mostly all backends - * which don't want to set a challenge - */ -NTSTATUS auth_get_challenge_not_implemented(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, DATA_BLOB *challenge) -{ - /* we don't want to set a challenge */ - return NT_STATUS_NOT_IMPLEMENTED; -} - -/**************************************************************************** - Create an auth_usersupplied_data structure after appropriate mapping. -****************************************************************************/ - -NTSTATUS map_user_info(TALLOC_CTX *mem_ctx, - const char *default_domain, - const struct auth_usersupplied_info *user_info, - struct auth_usersupplied_info **user_info_mapped) -{ - const char *domain; - char *account_name; - char *d; - DEBUG(5,("map_user_info: Mapping user [%s]\\[%s] from workstation [%s]\n", - user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name)); - - account_name = talloc_strdup(mem_ctx, user_info->client.account_name); - if (!account_name) { - return NT_STATUS_NO_MEMORY; - } - - /* don't allow "" as a domain, fixes a Win9X bug - where it doesn't supply a domain for logon script - 'net use' commands. */ - - /* Split user@realm names into user and realm components. This is TODO to fix with proper userprincipalname support */ - if (user_info->client.domain_name && *user_info->client.domain_name) { - domain = user_info->client.domain_name; - } else if (strchr_m(user_info->client.account_name, '@')) { - d = strchr_m(account_name, '@'); - if (!d) { - return NT_STATUS_INTERNAL_ERROR; - } - d[0] = '\0'; - d++; - domain = d; - } else { - domain = default_domain; - } - - *user_info_mapped = talloc(mem_ctx, struct auth_usersupplied_info); - if (!*user_info_mapped) { - return NT_STATUS_NO_MEMORY; - } - if (!talloc_reference(*user_info_mapped, user_info)) { - return NT_STATUS_NO_MEMORY; - } - **user_info_mapped = *user_info; - (*user_info_mapped)->mapped_state = true; - (*user_info_mapped)->mapped.domain_name = talloc_strdup(*user_info_mapped, domain); - (*user_info_mapped)->mapped.account_name = talloc_strdup(*user_info_mapped, account_name); - talloc_free(account_name); - if (!(*user_info_mapped)->mapped.domain_name - || !(*user_info_mapped)->mapped.account_name) { - return NT_STATUS_NO_MEMORY; - } - - return NT_STATUS_OK; -} - -/**************************************************************************** - Create an auth_usersupplied_data structure after appropriate mapping. -****************************************************************************/ - -NTSTATUS encrypt_user_info(TALLOC_CTX *mem_ctx, struct auth_context *auth_context, - enum auth_password_state to_state, - const struct auth_usersupplied_info *user_info_in, - const struct auth_usersupplied_info **user_info_encrypted) -{ - NTSTATUS nt_status; - struct auth_usersupplied_info *user_info_temp; - switch (to_state) { - case AUTH_PASSWORD_RESPONSE: - switch (user_info_in->password_state) { - case AUTH_PASSWORD_PLAIN: - { - const struct auth_usersupplied_info *user_info_temp2; - nt_status = encrypt_user_info(mem_ctx, auth_context, - AUTH_PASSWORD_HASH, - user_info_in, &user_info_temp2); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - user_info_in = user_info_temp2; - /* fall through */ - } - case AUTH_PASSWORD_HASH: - { - const uint8_t *challenge; - DATA_BLOB chall_blob; - user_info_temp = talloc(mem_ctx, struct auth_usersupplied_info); - if (!user_info_temp) { - return NT_STATUS_NO_MEMORY; - } - if (!talloc_reference(user_info_temp, user_info_in)) { - return NT_STATUS_NO_MEMORY; - } - *user_info_temp = *user_info_in; - user_info_temp->mapped_state = to_state; - - nt_status = auth_get_challenge(auth_context, &challenge); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - chall_blob = data_blob_talloc(mem_ctx, challenge, 8); - if (lp_client_ntlmv2_auth(auth_context->lp_ctx)) { - DATA_BLOB names_blob = NTLMv2_generate_names_blob(mem_ctx, lp_iconv_convenience(auth_context->lp_ctx), lp_netbios_name(auth_context->lp_ctx), lp_workgroup(auth_context->lp_ctx)); - DATA_BLOB lmv2_response, ntlmv2_response, lmv2_session_key, ntlmv2_session_key; - - if (!SMBNTLMv2encrypt_hash(user_info_temp, - user_info_in->client.account_name, - user_info_in->client.domain_name, - user_info_in->password.hash.nt->hash, &chall_blob, - &names_blob, - &lmv2_response, &ntlmv2_response, - &lmv2_session_key, &ntlmv2_session_key)) { - data_blob_free(&names_blob); - return NT_STATUS_NO_MEMORY; - } - data_blob_free(&names_blob); - user_info_temp->password.response.lanman = lmv2_response; - user_info_temp->password.response.nt = ntlmv2_response; - - data_blob_free(&lmv2_session_key); - data_blob_free(&ntlmv2_session_key); - } else { - DATA_BLOB blob = data_blob_talloc(mem_ctx, NULL, 24); - SMBOWFencrypt(user_info_in->password.hash.nt->hash, challenge, blob.data); - - user_info_temp->password.response.nt = blob; - if (lp_client_lanman_auth(auth_context->lp_ctx) && user_info_in->password.hash.lanman) { - DATA_BLOB lm_blob = data_blob_talloc(mem_ctx, NULL, 24); - SMBOWFencrypt(user_info_in->password.hash.lanman->hash, challenge, blob.data); - user_info_temp->password.response.lanman = lm_blob; - } else { - /* if not sending the LM password, send the NT password twice */ - user_info_temp->password.response.lanman = user_info_temp->password.response.nt; - } - } - - user_info_in = user_info_temp; - /* fall through */ - } - case AUTH_PASSWORD_RESPONSE: - *user_info_encrypted = user_info_in; - } - break; - case AUTH_PASSWORD_HASH: - { - switch (user_info_in->password_state) { - case AUTH_PASSWORD_PLAIN: - { - struct samr_Password lanman; - struct samr_Password nt; - - user_info_temp = talloc(mem_ctx, struct auth_usersupplied_info); - if (!user_info_temp) { - return NT_STATUS_NO_MEMORY; - } - if (!talloc_reference(user_info_temp, user_info_in)) { - return NT_STATUS_NO_MEMORY; - } - *user_info_temp = *user_info_in; - user_info_temp->mapped_state = to_state; - - if (E_deshash(user_info_in->password.plaintext, lanman.hash)) { - user_info_temp->password.hash.lanman = talloc(user_info_temp, - struct samr_Password); - *user_info_temp->password.hash.lanman = lanman; - } else { - user_info_temp->password.hash.lanman = NULL; - } - - E_md4hash(user_info_in->password.plaintext, nt.hash); - user_info_temp->password.hash.nt = talloc(user_info_temp, - struct samr_Password); - *user_info_temp->password.hash.nt = nt; - - user_info_in = user_info_temp; - /* fall through */ - } - case AUTH_PASSWORD_HASH: - *user_info_encrypted = user_info_in; - break; - default: - return NT_STATUS_INVALID_PARAMETER; - break; - } - break; - } - default: - return NT_STATUS_INVALID_PARAMETER; - } - - return NT_STATUS_OK; -} - - -/** - * Squash an NT_STATUS in line with security requirements. - * In an attempt to avoid giving the whole game away when users - * are authenticating, NT replaces both NT_STATUS_NO_SUCH_USER and - * NT_STATUS_WRONG_PASSWORD with NT_STATUS_LOGON_FAILURE in certain situations - * (session setups in particular). - * - * @param nt_status NTSTATUS input for squashing. - * @return the 'squashed' nt_status - **/ -_PUBLIC_ NTSTATUS auth_nt_status_squash(NTSTATUS nt_status) -{ - if NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER) { - /* Match WinXP and don't give the game away */ - return NT_STATUS_LOGON_FAILURE; - } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) { - /* Match WinXP and don't give the game away */ - return NT_STATUS_LOGON_FAILURE; - } - - return nt_status; -} diff --git a/source4/auth/auth_winbind.c b/source4/auth/auth_winbind.c deleted file mode 100644 index 149f549afa..0000000000 --- a/source4/auth/auth_winbind.c +++ /dev/null @@ -1,282 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - Winbind authentication mechnism - - Copyright (C) Tim Potter 2000 - Copyright (C) Andrew Bartlett 2001 - 2002 - Copyright (C) Stefan Metzmacher 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 3 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, see . -*/ - -#include "includes.h" -#include "auth/auth.h" -#include "auth/auth_proto.h" -#include "auth/session_proto.h" -#include "nsswitch/winbind_client.h" -#include "librpc/gen_ndr/ndr_netlogon.h" -#include "librpc/gen_ndr/ndr_winbind.h" -#include "lib/messaging/irpc.h" -#include "param/param.h" - -static NTSTATUS get_info3_from_ndr(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience, struct winbindd_response *response, struct netr_SamInfo3 *info3) -{ - size_t len = response->length - sizeof(struct winbindd_response); - if (len > 4) { - enum ndr_err_code ndr_err; - DATA_BLOB blob; - blob.length = len - 4; - blob.data = (uint8_t *)(((char *)response->extra_data.data) + 4); - - ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, - iconv_convenience, info3, - (ndr_pull_flags_fn_t)ndr_pull_netr_SamInfo3); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return ndr_map_error2ntstatus(ndr_err); - } - - return NT_STATUS_OK; - } else { - DEBUG(2, ("get_info3_from_ndr: No info3 struct found!\n")); - return NT_STATUS_UNSUCCESSFUL; - } -} - -static NTSTATUS winbind_want_check(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info) -{ - if (!user_info->mapped.account_name || !*user_info->mapped.account_name) { - return NT_STATUS_NOT_IMPLEMENTED; - } - - /* TODO: maybe limit the user scope to remote users only */ - return NT_STATUS_OK; -} - -/* - Authenticate a user with a challenge/response - using the samba3 winbind protocol -*/ -static NTSTATUS winbind_check_password_samba3(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info, - struct auth_serversupplied_info **server_info) -{ - struct winbindd_request request; - struct winbindd_response response; - NSS_STATUS result; - NTSTATUS nt_status; - struct netr_SamInfo3 info3; - - /* Send off request */ - const struct auth_usersupplied_info *user_info_temp; - nt_status = encrypt_user_info(mem_ctx, ctx->auth_ctx, - AUTH_PASSWORD_RESPONSE, - user_info, &user_info_temp); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - user_info = user_info_temp; - - ZERO_STRUCT(request); - ZERO_STRUCT(response); - request.flags = WBFLAG_PAM_INFO3_NDR; - - request.data.auth_crap.logon_parameters = user_info->logon_parameters; - - safe_strcpy(request.data.auth_crap.user, - user_info->client.account_name, sizeof(fstring)); - safe_strcpy(request.data.auth_crap.domain, - user_info->client.domain_name, sizeof(fstring)); - safe_strcpy(request.data.auth_crap.workstation, - user_info->workstation_name, sizeof(fstring)); - - memcpy(request.data.auth_crap.chal, ctx->auth_ctx->challenge.data.data, sizeof(request.data.auth_crap.chal)); - - request.data.auth_crap.lm_resp_len = MIN(user_info->password.response.lanman.length, - sizeof(request.data.auth_crap.lm_resp)); - request.data.auth_crap.nt_resp_len = MIN(user_info->password.response.nt.length, - sizeof(request.data.auth_crap.nt_resp)); - - memcpy(request.data.auth_crap.lm_resp, user_info->password.response.lanman.data, - request.data.auth_crap.lm_resp_len); - memcpy(request.data.auth_crap.nt_resp, user_info->password.response.nt.data, - request.data.auth_crap.nt_resp_len); - - result = winbindd_request_response(WINBINDD_PAM_AUTH_CRAP, &request, &response); - - nt_status = NT_STATUS(response.data.auth.nt_status); - NT_STATUS_NOT_OK_RETURN(nt_status); - - if (result == NSS_STATUS_SUCCESS && response.extra_data.data) { - union netr_Validation validation; - - nt_status = get_info3_from_ndr(mem_ctx, lp_iconv_convenience(ctx->auth_ctx->lp_ctx), &response, &info3); - SAFE_FREE(response.extra_data.data); - NT_STATUS_NOT_OK_RETURN(nt_status); - - validation.sam3 = &info3; - nt_status = make_server_info_netlogon_validation(mem_ctx, - user_info->client.account_name, - 3, &validation, - server_info); - return nt_status; - } else if (result == NSS_STATUS_SUCCESS && !response.extra_data.data) { - DEBUG(0, ("Winbindd authenticated the user [%s]\\[%s], " - "but did not include the required info3 reply!\n", - user_info->client.domain_name, user_info->client.account_name)); - return NT_STATUS_INSUFFICIENT_LOGON_INFO; - } else if (NT_STATUS_IS_OK(nt_status)) { - DEBUG(1, ("Winbindd authentication for [%s]\\[%s] failed, " - "but no error code is available!\n", - user_info->client.domain_name, user_info->client.account_name)); - return NT_STATUS_NO_LOGON_SERVERS; - } - - return nt_status; -} - -struct winbind_check_password_state { - struct winbind_SamLogon req; -}; - -/* - Authenticate a user with a challenge/response - using IRPC to the winbind task -*/ -static NTSTATUS winbind_check_password(struct auth_method_context *ctx, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info, - struct auth_serversupplied_info **server_info) -{ - NTSTATUS status; - struct server_id *winbind_servers; - struct winbind_check_password_state *s; - const struct auth_usersupplied_info *user_info_new; - struct netr_IdentityInfo *identity_info; - - s = talloc(mem_ctx, struct winbind_check_password_state); - NT_STATUS_HAVE_NO_MEMORY(s); - - winbind_servers = irpc_servers_byname(ctx->auth_ctx->msg_ctx, s, "winbind_server"); - if ((winbind_servers == NULL) || (winbind_servers[0].id == 0)) { - DEBUG(0, ("Winbind authentication for [%s]\\[%s] failed, " - "no winbind_server running!\n", - user_info->client.domain_name, user_info->client.account_name)); - return NT_STATUS_NO_LOGON_SERVERS; - } - - if (user_info->flags & USER_INFO_INTERACTIVE_LOGON) { - struct netr_PasswordInfo *password_info; - - status = encrypt_user_info(s, ctx->auth_ctx, AUTH_PASSWORD_HASH, - user_info, &user_info_new); - NT_STATUS_NOT_OK_RETURN(status); - user_info = user_info_new; - - password_info = talloc(s, struct netr_PasswordInfo); - NT_STATUS_HAVE_NO_MEMORY(password_info); - - password_info->lmpassword = *user_info->password.hash.lanman; - password_info->ntpassword = *user_info->password.hash.nt; - - identity_info = &password_info->identity_info; - s->req.in.logon_level = 1; - s->req.in.logon.password= password_info; - } else { - struct netr_NetworkInfo *network_info; - const uint8_t *challenge; - - status = encrypt_user_info(s, ctx->auth_ctx, AUTH_PASSWORD_RESPONSE, - user_info, &user_info_new); - NT_STATUS_NOT_OK_RETURN(status); - user_info = user_info_new; - - network_info = talloc(s, struct netr_NetworkInfo); - NT_STATUS_HAVE_NO_MEMORY(network_info); - - status = auth_get_challenge(ctx->auth_ctx, &challenge); - NT_STATUS_NOT_OK_RETURN(status); - - memcpy(network_info->challenge, challenge, sizeof(network_info->challenge)); - - network_info->nt.length = user_info->password.response.nt.length; - network_info->nt.data = user_info->password.response.nt.data; - - network_info->lm.length = user_info->password.response.lanman.length; - network_info->lm.data = user_info->password.response.lanman.data; - - identity_info = &network_info->identity_info; - s->req.in.logon_level = 2; - s->req.in.logon.network = network_info; - } - - identity_info->domain_name.string = user_info->client.domain_name; - identity_info->parameter_control = user_info->logon_parameters; /* see MSV1_0_* */ - identity_info->logon_id_low = 0; - identity_info->logon_id_high = 0; - identity_info->account_name.string = user_info->client.account_name; - identity_info->workstation.string = user_info->workstation_name; - - s->req.in.validation_level = 3; - - status = IRPC_CALL(ctx->auth_ctx->msg_ctx, winbind_servers[0], - winbind, WINBIND_SAMLOGON, - &s->req, s); - NT_STATUS_NOT_OK_RETURN(status); - - status = make_server_info_netlogon_validation(mem_ctx, - user_info->client.account_name, - s->req.in.validation_level, - &s->req.out.validation, - server_info); - NT_STATUS_NOT_OK_RETURN(status); - - return NT_STATUS_OK; -} - -static const struct auth_operations winbind_samba3_ops = { - .name = "winbind_samba3", - .get_challenge = auth_get_challenge_not_implemented, - .want_check = winbind_want_check, - .check_password = winbind_check_password_samba3 -}; - -static const struct auth_operations winbind_ops = { - .name = "winbind", - .get_challenge = auth_get_challenge_not_implemented, - .want_check = winbind_want_check, - .check_password = winbind_check_password -}; - -_PUBLIC_ NTSTATUS auth_winbind_init(void) -{ - NTSTATUS ret; - - ret = auth_register(&winbind_samba3_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register 'winbind_samba3' auth backend!\n")); - return ret; - } - - ret = auth_register(&winbind_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register 'winbind' auth backend!\n")); - return ret; - } - - return NT_STATUS_OK; -} diff --git a/source4/auth/config.mk b/source4/auth/config.mk index 0acb9e30ba..87b796288d 100644 --- a/source4/auth/config.mk +++ b/source4/auth/config.mk @@ -2,6 +2,7 @@ mkinclude gensec/config.mk mkinclude kerberos/config.mk mkinclude ntlmssp/config.mk +mkinclude ntlm/config.mk mkinclude credentials/config.mk [SUBSYSTEM::auth_session] @@ -24,93 +25,13 @@ PRIVATE_PROTO_HEADER = auth_sam.h PUBLIC_DEPENDENCIES = SAMDB UTIL_LDB LIBSECURITY PRIVATE_DEPENDENCIES = LDAP_ENCODE -auth_sam_OBJ_FILES = $(addprefix auth/, sam.o ntlm_check.o) +auth_sam_OBJ_FILES = $(addprefix auth/, sam.o) [SUBSYSTEM::auth_sam_reply] PRIVATE_PROTO_HEADER = auth_sam_reply.h auth_sam_reply_OBJ_FILES = $(addprefix auth/, auth_sam_reply.o) -####################### -# Start MODULE auth_sam -[MODULE::auth_sam_module] -# gensec_krb5 and gensec_gssapi depend on it -INIT_FUNCTION = auth_sam_init -SUBSYSTEM = auth -PRIVATE_DEPENDENCIES = \ - SAMDB auth_sam -# End MODULE auth_sam -####################### - -auth_sam_module_OBJ_FILES = $(addprefix auth/, auth_sam.o) - -####################### -# Start MODULE auth_anonymous -[MODULE::auth_anonymous] -INIT_FUNCTION = auth_anonymous_init -SUBSYSTEM = auth -# End MODULE auth_anonymous -####################### - -auth_anonymous_OBJ_FILES = $(addprefix auth/, auth_anonymous.o) - -####################### -# Start MODULE auth_anonymous -[MODULE::auth_server] -INIT_FUNCTION = auth_server_init -SUBSYSTEM = auth -PRIVATE_DEPENDENCIES = LIBSAMBA-UTIL LIBCLI_SMB -OUTPUT_TYPE = SHARED_LIBRARY -# End MODULE auth_server -####################### - -auth_server_OBJ_FILES = $(addprefix auth/, auth_server.o) - -####################### -# Start MODULE auth_winbind -[MODULE::auth_winbind] -INIT_FUNCTION = auth_winbind_init -SUBSYSTEM = auth -PRIVATE_DEPENDENCIES = NDR_WINBIND MESSAGING LIBWINBIND-CLIENT -# End MODULE auth_winbind -####################### - -auth_winbind_OBJ_FILES = $(addprefix auth/, auth_winbind.o) - -####################### -# Start MODULE auth_developer -[MODULE::auth_developer] -INIT_FUNCTION = auth_developer_init -SUBSYSTEM = auth -# End MODULE auth_developer -####################### - -auth_developer_OBJ_FILES = $(addprefix auth/, auth_developer.o) - -[MODULE::auth_unix] -INIT_FUNCTION = auth_unix_init -SUBSYSTEM = auth -PRIVATE_DEPENDENCIES = CRYPT PAM PAM_ERRORS NSS_WRAPPER - -auth_unix_OBJ_FILES = $(addprefix auth/, auth_unix.o) - -[SUBSYSTEM::PAM_ERRORS] -PRIVATE_PROTO_HEADER = pam_errors.h - -#VERSION = 0.0.1 -#SO_VERSION = 0 -PAM_ERRORS_OBJ_FILES = $(addprefix auth/, pam_errors.o) - -[MODULE::auth] -INIT_FUNCTION = server_service_auth_init -SUBSYSTEM = service -PRIVATE_PROTO_HEADER = auth_proto.h -PRIVATE_DEPENDENCIES = LIBSAMBA-UTIL LIBSECURITY SAMDB CREDENTIALS - -auth_OBJ_FILES = $(addprefix auth/, auth.o auth_util.o auth_simple.o) - -# PUBLIC_HEADERS += auth/auth.h - [PYTHON::swig_auth] PUBLIC_DEPENDENCIES = auth_system_session PRIVATE_DEPENDENCIES = SAMDB diff --git a/source4/auth/ntlm/auth.c b/source4/auth/ntlm/auth.c new file mode 100644 index 0000000000..b74a438962 --- /dev/null +++ b/source4/auth/ntlm/auth.c @@ -0,0 +1,539 @@ +/* + Unix SMB/CIFS implementation. + Password and authentication handling + Copyright (C) Andrew Bartlett 2001-2002 + Copyright (C) Stefan Metzmacher 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 3 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, see . +*/ + +#include "includes.h" +#include "lib/util/dlinklist.h" +#include "auth/auth.h" +#include "auth/auth_proto.h" +#include "lib/events/events.h" +#include "build.h" +#include "param/param.h" + +/*************************************************************************** + Set a fixed challenge +***************************************************************************/ +_PUBLIC_ NTSTATUS auth_context_set_challenge(struct auth_context *auth_ctx, const uint8_t chal[8], const char *set_by) +{ + auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by); + NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by); + + auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8); + NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data); + + return NT_STATUS_OK; +} + +/*************************************************************************** + Set a fixed challenge +***************************************************************************/ +bool auth_challenge_may_be_modified(struct auth_context *auth_ctx) +{ + return auth_ctx->challenge.may_be_modified; +} + +/**************************************************************************** + Try to get a challenge out of the various authentication modules. + Returns a const char of length 8 bytes. +****************************************************************************/ +_PUBLIC_ NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, const uint8_t **_chal) +{ + NTSTATUS nt_status; + struct auth_method_context *method; + + if (auth_ctx->challenge.data.length) { + DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n", + auth_ctx->challenge.set_by)); + *_chal = auth_ctx->challenge.data.data; + return NT_STATUS_OK; + } + + for (method = auth_ctx->methods; method; method = method->next) { + DATA_BLOB challenge = data_blob(NULL,0); + + nt_status = method->ops->get_challenge(method, auth_ctx, &challenge); + if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) { + continue; + } + + NT_STATUS_NOT_OK_RETURN(nt_status); + + if (challenge.length != 8) { + DEBUG(0, ("auth_get_challenge: invalid challenge (length %u) by mothod [%s]\n", + (unsigned)challenge.length, method->ops->name)); + return NT_STATUS_INTERNAL_ERROR; + } + + auth_ctx->challenge.data = challenge; + auth_ctx->challenge.set_by = method->ops->name; + + break; + } + + if (!auth_ctx->challenge.set_by) { + uint8_t chal[8]; + generate_random_buffer(chal, 8); + + auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8); + NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data); + auth_ctx->challenge.set_by = "random"; + + auth_ctx->challenge.may_be_modified = true; + } + + DEBUG(10,("auth_get_challenge: challenge set by %s\n", + auth_ctx->challenge.set_by)); + + *_chal = auth_ctx->challenge.data.data; + return NT_STATUS_OK; +} + +struct auth_check_password_sync_state { + bool finished; + NTSTATUS status; + struct auth_serversupplied_info *server_info; +}; + +static void auth_check_password_sync_callback(struct auth_check_password_request *req, + void *private_data) +{ + struct auth_check_password_sync_state *s = talloc_get_type(private_data, + struct auth_check_password_sync_state); + + s->finished = true; + s->status = auth_check_password_recv(req, s, &s->server_info); +} + +/** + * Check a user's Plaintext, LM or NTLM password. + * (sync version) + * + * Check a user's password, as given in the user_info struct and return various + * interesting details in the server_info struct. + * + * The return value takes precedence over the contents of the server_info + * struct. When the return is other than NT_STATUS_OK the contents + * of that structure is undefined. + * + * @param auth_ctx Supplies the challenges and some other data. + * Must be created with auth_context_create(), and the challenges should be + * filled in, either at creation or by calling the challenge geneation + * function auth_get_challenge(). + * + * @param user_info Contains the user supplied components, including the passwords. + * + * @param mem_ctx The parent memory context for the server_info structure + * + * @param server_info If successful, contains information about the authentication, + * including a SAM_ACCOUNT struct describing the user. + * + * @return An NTSTATUS with NT_STATUS_OK or an appropriate error. + * + **/ + +_PUBLIC_ NTSTATUS auth_check_password(struct auth_context *auth_ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info, + struct auth_serversupplied_info **server_info) +{ + struct auth_check_password_sync_state *sync_state; + NTSTATUS status; + + sync_state = talloc_zero(auth_ctx, struct auth_check_password_sync_state); + NT_STATUS_HAVE_NO_MEMORY(sync_state); + + auth_check_password_send(auth_ctx, user_info, auth_check_password_sync_callback, sync_state); + + while (!sync_state->finished) { + event_loop_once(auth_ctx->event_ctx); + } + + status = sync_state->status; + + if (NT_STATUS_IS_OK(status)) { + *server_info = talloc_steal(mem_ctx, sync_state->server_info); + } + + talloc_free(sync_state); + return status; +} + +struct auth_check_password_request { + struct auth_context *auth_ctx; + const struct auth_usersupplied_info *user_info; + struct auth_serversupplied_info *server_info; + struct auth_method_context *method; + NTSTATUS status; + struct { + void (*fn)(struct auth_check_password_request *req, void *private_data); + void *private_data; + } callback; +}; + +static void auth_check_password_async_timed_handler(struct event_context *ev, struct timed_event *te, + struct timeval t, void *ptr) +{ + struct auth_check_password_request *req = talloc_get_type(ptr, struct auth_check_password_request); + req->status = req->method->ops->check_password(req->method, req, req->user_info, &req->server_info); + req->callback.fn(req, req->callback.private_data); +} + +/** + * Check a user's Plaintext, LM or NTLM password. + * async send hook + * + * Check a user's password, as given in the user_info struct and return various + * interesting details in the server_info struct. + * + * The return value takes precedence over the contents of the server_info + * struct. When the return is other than NT_STATUS_OK the contents + * of that structure is undefined. + * + * @param auth_ctx Supplies the challenges and some other data. + * Must be created with make_auth_context(), and the challenges should be + * filled in, either at creation or by calling the challenge geneation + * function auth_get_challenge(). + * + * @param user_info Contains the user supplied components, including the passwords. + * + * @param callback A callback function which will be called when the operation is finished. + * The callback function needs to call auth_check_password_recv() to get the return values + * + * @param private_data A private pointer which will ba passed to the callback function + * + **/ + +_PUBLIC_ void auth_check_password_send(struct auth_context *auth_ctx, + const struct auth_usersupplied_info *user_info, + void (*callback)(struct auth_check_password_request *req, void *private_data), + void *private_data) +{ + /* if all the modules say 'not for me' this is reasonable */ + NTSTATUS nt_status; + struct auth_method_context *method; + const uint8_t *challenge; + struct auth_usersupplied_info *user_info_tmp; + struct auth_check_password_request *req = NULL; + + DEBUG(3, ("auth_check_password_send: Checking password for unmapped user [%s]\\[%s]@[%s]\n", + user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name)); + + req = talloc_zero(auth_ctx, struct auth_check_password_request); + if (!req) { + callback(NULL, private_data); + return; + } + req->auth_ctx = auth_ctx; + req->user_info = user_info; + req->callback.fn = callback; + req->callback.private_data = private_data; + + if (!user_info->mapped_state) { + nt_status = map_user_info(req, lp_workgroup(auth_ctx->lp_ctx), user_info, &user_info_tmp); + if (!NT_STATUS_IS_OK(nt_status)) goto failed; + user_info = user_info_tmp; + req->user_info = user_info_tmp; + } + + DEBUGADD(3,("auth_check_password_send: mapped user is: [%s]\\[%s]@[%s]\n", + user_info->mapped.domain_name, user_info->mapped.account_name, user_info->workstation_name)); + + nt_status = auth_get_challenge(auth_ctx, &challenge); + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(0, ("auth_check_password_send: Invalid challenge (length %u) stored for this auth context set_by %s - cannot continue: %s\n", + (unsigned)auth_ctx->challenge.data.length, auth_ctx->challenge.set_by, nt_errstr(nt_status))); + goto failed; + } + + if (auth_ctx->challenge.set_by) { + DEBUG(10, ("auth_check_password_send: auth_context challenge created by %s\n", + auth_ctx->challenge.set_by)); + } + + DEBUG(10, ("auth_check_password_send: challenge is: \n")); + dump_data(5, auth_ctx->challenge.data.data, auth_ctx->challenge.data.length); + + nt_status = NT_STATUS_NO_SUCH_USER; /* If all the modules say 'not for me', then this is reasonable */ + for (method = auth_ctx->methods; method; method = method->next) { + NTSTATUS result; + struct timed_event *te = NULL; + + /* check if the module wants to chek the password */ + result = method->ops->want_check(method, req, user_info); + if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) { + DEBUG(11,("auth_check_password_send: %s had nothing to say\n", method->ops->name)); + continue; + } + + nt_status = result; + req->method = method; + + if (!NT_STATUS_IS_OK(nt_status)) break; + + te = event_add_timed(auth_ctx->event_ctx, req, + timeval_zero(), + auth_check_password_async_timed_handler, req); + if (!te) { + nt_status = NT_STATUS_NO_MEMORY; + goto failed; + } + return; + } + +failed: + req->status = nt_status; + req->callback.fn(req, req->callback.private_data); +} + +/** + * Check a user's Plaintext, LM or NTLM password. + * async receive function + * + * The return value takes precedence over the contents of the server_info + * struct. When the return is other than NT_STATUS_OK the contents + * of that structure is undefined. + * + * + * @param req The async auth_check_password state, passes to the callers callback function + * + * @param mem_ctx The parent memory context for the server_info structure + * + * @param server_info If successful, contains information about the authentication, + * including a SAM_ACCOUNT struct describing the user. + * + * @return An NTSTATUS with NT_STATUS_OK or an appropriate error. + * + **/ + +_PUBLIC_ NTSTATUS auth_check_password_recv(struct auth_check_password_request *req, + TALLOC_CTX *mem_ctx, + struct auth_serversupplied_info **server_info) +{ + NTSTATUS status; + + NT_STATUS_HAVE_NO_MEMORY(req); + + if (NT_STATUS_IS_OK(req->status)) { + DEBUG(5,("auth_check_password_recv: %s authentication for user [%s\\%s] succeeded\n", + req->method->ops->name, req->server_info->domain_name, req->server_info->account_name)); + + *server_info = talloc_steal(mem_ctx, req->server_info); + } else { + DEBUG(2,("auth_check_password_recv: %s authentication for user [%s\\%s] FAILED with error %s\n", + (req->method ? req->method->ops->name : "NO_METHOD"), + req->user_info->mapped.domain_name, + req->user_info->mapped.account_name, + nt_errstr(req->status))); + } + + status = req->status; + talloc_free(req); + return status; +} + +/*************************************************************************** + Make a auth_info struct for the auth subsystem + - Allow the caller to specify the methods to use +***************************************************************************/ +_PUBLIC_ NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char **methods, + struct event_context *ev, + struct messaging_context *msg, + struct loadparm_context *lp_ctx, + struct auth_context **auth_ctx) +{ + int i; + struct auth_context *ctx; + + if (!methods) { + DEBUG(0,("auth_context_create: No auth method list!?\n")); + return NT_STATUS_INTERNAL_ERROR; + } + + if (!ev) { + DEBUG(0,("auth_context_create: called with out event context\n")); + return NT_STATUS_INTERNAL_ERROR; + } + + if (!msg) { + DEBUG(0,("auth_context_create: called with out messaging context\n")); + return NT_STATUS_INTERNAL_ERROR; + } + + ctx = talloc(mem_ctx, struct auth_context); + NT_STATUS_HAVE_NO_MEMORY(ctx); + ctx->challenge.set_by = NULL; + ctx->challenge.may_be_modified = false; + ctx->challenge.data = data_blob(NULL, 0); + ctx->methods = NULL; + ctx->event_ctx = ev; + ctx->msg_ctx = msg; + ctx->lp_ctx = lp_ctx; + + for (i=0; methods[i] ; i++) { + struct auth_method_context *method; + + method = talloc(ctx, struct auth_method_context); + NT_STATUS_HAVE_NO_MEMORY(method); + + method->ops = auth_backend_byname(methods[i]); + if (!method->ops) { + DEBUG(1,("auth_context_create: failed to find method=%s\n", + methods[i])); + return NT_STATUS_INTERNAL_ERROR; + } + method->auth_ctx = ctx; + method->depth = i; + DLIST_ADD_END(ctx->methods, method, struct auth_method_context *); + } + + if (!ctx->methods) { + return NT_STATUS_INTERNAL_ERROR; + } + + *auth_ctx = ctx; + + return NT_STATUS_OK; +} +/*************************************************************************** + Make a auth_info struct for the auth subsystem + - Uses default auth_methods, depending on server role and smb.conf settings +***************************************************************************/ +_PUBLIC_ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct messaging_context *msg, + struct loadparm_context *lp_ctx, + struct auth_context **auth_ctx) +{ + const char **auth_methods = NULL; + switch (lp_server_role(lp_ctx)) { + case ROLE_STANDALONE: + auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "standalone", NULL); + break; + case ROLE_DOMAIN_MEMBER: + auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "member server", NULL); + break; + case ROLE_DOMAIN_CONTROLLER: + auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "domain controller", NULL); + break; + } + return auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, auth_ctx); +} + + +/* the list of currently registered AUTH backends */ +static struct auth_backend { + const struct auth_operations *ops; +} *backends = NULL; +static int num_backends; + +/* + register a AUTH backend. + + The 'name' can be later used by other backends to find the operations + structure for this backend. +*/ +_PUBLIC_ NTSTATUS auth_register(const struct auth_operations *ops) +{ + struct auth_operations *new_ops; + + if (auth_backend_byname(ops->name) != NULL) { + /* its already registered! */ + DEBUG(0,("AUTH backend '%s' already registered\n", + ops->name)); + return NT_STATUS_OBJECT_NAME_COLLISION; + } + + backends = talloc_realloc(talloc_autofree_context(), backends, + struct auth_backend, num_backends+1); + NT_STATUS_HAVE_NO_MEMORY(backends); + + new_ops = talloc_memdup(backends, ops, sizeof(*ops)); + NT_STATUS_HAVE_NO_MEMORY(new_ops); + new_ops->name = talloc_strdup(new_ops, ops->name); + NT_STATUS_HAVE_NO_MEMORY(new_ops->name); + + backends[num_backends].ops = new_ops; + + num_backends++; + + DEBUG(3,("AUTH backend '%s' registered\n", + ops->name)); + + return NT_STATUS_OK; +} + +/* + return the operations structure for a named backend of the specified type +*/ +const struct auth_operations *auth_backend_byname(const char *name) +{ + int i; + + for (i=0;iname, name) == 0) { + return backends[i].ops; + } + } + + return NULL; +} + +/* + return the AUTH interface version, and the size of some critical types + This can be used by backends to either detect compilation errors, or provide + multiple implementations for different smbd compilation options in one module +*/ +const struct auth_critical_sizes *auth_interface_version(void) +{ + static const struct auth_critical_sizes critical_sizes = { + AUTH_INTERFACE_VERSION, + sizeof(struct auth_operations), + sizeof(struct auth_method_context), + sizeof(struct auth_context), + sizeof(struct auth_usersupplied_info), + sizeof(struct auth_serversupplied_info) + }; + + return &critical_sizes; +} + +_PUBLIC_ NTSTATUS auth_init(void) +{ + static bool initialized = false; + extern NTSTATUS auth_developer_init(void); + extern NTSTATUS auth_winbind_init(void); + extern NTSTATUS auth_anonymous_init(void); + extern NTSTATUS auth_unix_init(void); + extern NTSTATUS auth_sam_init(void); + extern NTSTATUS auth_server_init(void); + + init_module_fn static_init[] = { STATIC_auth_MODULES }; + + if (initialized) return NT_STATUS_OK; + initialized = true; + + run_init_functions(static_init); + + return NT_STATUS_OK; +} + +NTSTATUS server_service_auth_init(void) +{ + return auth_init(); +} diff --git a/source4/auth/ntlm/auth_anonymous.c b/source4/auth/ntlm/auth_anonymous.c new file mode 100644 index 0000000000..b93c7c2008 --- /dev/null +++ b/source4/auth/ntlm/auth_anonymous.c @@ -0,0 +1,78 @@ +/* + Unix SMB/CIFS implementation. + + Anonymous Authentification + + Copyright (C) Stefan Metzmacher 2004-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 3 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, see . +*/ + +#include "includes.h" +#include "auth/auth.h" +#include "auth/auth_proto.h" +#include "param/param.h" + +/** + * Return a anonymous logon for anonymous users (username = "") + * + * Typically used as the first module in the auth chain, this allows + * anonymou logons to be dealt with in one place. Non-anonymou logons 'fail' + * and pass onto the next module. + **/ +static NTSTATUS anonymous_want_check(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info) +{ + if (user_info->client.account_name && *user_info->client.account_name) { + return NT_STATUS_NOT_IMPLEMENTED; + } + + return NT_STATUS_OK; +} + +/** + * Return a anonymous logon for anonymous users (username = "") + * + * Typically used as the first module in the auth chain, this allows + * anonymou logons to be dealt with in one place. Non-anonymou logons 'fail' + * and pass onto the next module. + **/ +static NTSTATUS anonymous_check_password(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info, + struct auth_serversupplied_info **_server_info) +{ + return auth_anonymous_server_info(mem_ctx, lp_netbios_name(ctx->auth_ctx->lp_ctx), _server_info); +} + +static const struct auth_operations anonymous_auth_ops = { + .name = "anonymous", + .get_challenge = auth_get_challenge_not_implemented, + .want_check = anonymous_want_check, + .check_password = anonymous_check_password +}; + +_PUBLIC_ NTSTATUS auth_anonymous_init(void) +{ + NTSTATUS ret; + + ret = auth_register(&anonymous_auth_ops); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(0,("Failed to register 'anonymous' auth backend!\n")); + return ret; + } + + return ret; +} diff --git a/source4/auth/ntlm/auth_developer.c b/source4/auth/ntlm/auth_developer.c new file mode 100644 index 0000000000..a2c9cbc828 --- /dev/null +++ b/source4/auth/ntlm/auth_developer.c @@ -0,0 +1,207 @@ +/* + Unix SMB/CIFS implementation. + Generic authentication types + Copyright (C) Andrew Bartlett 2001-2002 + Copyright (C) Jelmer Vernooij 2002 + Copyright (C) Stefan Metzmacher 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 3 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, see . +*/ + +#include "includes.h" +#include "auth/auth.h" +#include "auth/auth_proto.h" +#include "libcli/security/security.h" +#include "librpc/gen_ndr/ndr_samr.h" + +static NTSTATUS name_to_ntstatus_want_check(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info) +{ + return NT_STATUS_OK; +} + +/** + * Return an error based on username + * + * This function allows the testing of obsure errors, as well as the generation + * of NT_STATUS -> DOS error mapping tables. + * + * This module is of no value to end-users. + * + * The password is ignored. + * + * @return An NTSTATUS value based on the username + **/ + +static NTSTATUS name_to_ntstatus_check_password(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info, + struct auth_serversupplied_info **_server_info) +{ + NTSTATUS nt_status; + struct auth_serversupplied_info *server_info; + uint32_t error_num; + const char *user; + + user = user_info->client.account_name; + + if (strncasecmp("NT_STATUS", user, strlen("NT_STATUS")) == 0) { + nt_status = nt_status_string_to_code(user); + } else { + error_num = strtoul(user, NULL, 16); + DEBUG(5,("name_to_ntstatus_check_password: Error for user %s was 0x%08X\n", user, error_num)); + nt_status = NT_STATUS(error_num); + } + NT_STATUS_NOT_OK_RETURN(nt_status); + + server_info = talloc(mem_ctx, struct auth_serversupplied_info); + NT_STATUS_HAVE_NO_MEMORY(server_info); + + server_info->account_sid = dom_sid_parse_talloc(server_info, SID_NT_ANONYMOUS); + NT_STATUS_HAVE_NO_MEMORY(server_info->account_sid); + + /* is this correct? */ + server_info->primary_group_sid = dom_sid_parse_talloc(server_info, SID_BUILTIN_GUESTS); + NT_STATUS_HAVE_NO_MEMORY(server_info->primary_group_sid); + + server_info->n_domain_groups = 0; + server_info->domain_groups = NULL; + + /* annoying, but the Anonymous really does have a session key, + and it is all zeros! */ + server_info->user_session_key = data_blob_talloc(server_info, NULL, 16); + NT_STATUS_HAVE_NO_MEMORY(server_info->user_session_key.data); + + server_info->lm_session_key = data_blob_talloc(server_info, NULL, 16); + NT_STATUS_HAVE_NO_MEMORY(server_info->lm_session_key.data); + + data_blob_clear(&server_info->user_session_key); + data_blob_clear(&server_info->lm_session_key); + + server_info->account_name = talloc_asprintf(server_info, "NAME TO NTSTATUS %s ANONYMOUS LOGON", user); + NT_STATUS_HAVE_NO_MEMORY(server_info->account_name); + + server_info->domain_name = talloc_strdup(server_info, "NT AUTHORITY"); + NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name); + + server_info->full_name = talloc_asprintf(server_info, "NAME TO NTSTATUS %s Anonymous Logon", user); + NT_STATUS_HAVE_NO_MEMORY(server_info->full_name); + + server_info->logon_script = talloc_strdup(server_info, ""); + NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script); + + server_info->profile_path = talloc_strdup(server_info, ""); + NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path); + + server_info->home_directory = talloc_strdup(server_info, ""); + NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory); + + server_info->home_drive = talloc_strdup(server_info, ""); + NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive); + + server_info->last_logon = 0; + server_info->last_logoff = 0; + server_info->acct_expiry = 0; + server_info->last_password_change = 0; + server_info->allow_password_change = 0; + server_info->force_password_change = 0; + + server_info->logon_count = 0; + server_info->bad_password_count = 0; + + server_info->acct_flags = ACB_NORMAL; + + server_info->authenticated = false; + + *_server_info = server_info; + + return nt_status; +} + +static const struct auth_operations name_to_ntstatus_auth_ops = { + .name = "name_to_ntstatus", + .get_challenge = auth_get_challenge_not_implemented, + .want_check = name_to_ntstatus_want_check, + .check_password = name_to_ntstatus_check_password +}; + +/** + * Return a 'fixed' challenge instead of a variable one. + * + * The idea of this function is to make packet snifs consistant + * with a fixed challenge, so as to aid debugging. + * + * This module is of no value to end-users. + * + * This module does not actually authenticate the user, but + * just pretenteds to need a specified challenge. + * This module removes *all* security from the challenge-response system + * + * @return NT_STATUS_UNSUCCESSFUL + **/ +static NTSTATUS fixed_challenge_get_challenge(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, DATA_BLOB *_blob) +{ + DATA_BLOB blob; + const char *challenge = "I am a teapot"; + + blob = data_blob_talloc(mem_ctx, challenge, 8); + NT_STATUS_HAVE_NO_MEMORY(blob.data); + + *_blob = blob; + return NT_STATUS_OK; +} + +static NTSTATUS fixed_challenge_want_check(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info) +{ + /* don't handle any users */ + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS fixed_challenge_check_password(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info, + struct auth_serversupplied_info **_server_info) +{ + /* don't handle any users */ + return NT_STATUS_NO_SUCH_USER; +} + +static const struct auth_operations fixed_challenge_auth_ops = { + .name = "fixed_challenge", + .get_challenge = fixed_challenge_get_challenge, + .want_check = fixed_challenge_want_check, + .check_password = fixed_challenge_check_password +}; + +_PUBLIC_ NTSTATUS auth_developer_init(void) +{ + NTSTATUS ret; + + ret = auth_register(&name_to_ntstatus_auth_ops); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(0,("Failed to register 'name_to_ntstatus' auth backend!\n")); + return ret; + } + + ret = auth_register(&fixed_challenge_auth_ops); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(0,("Failed to register 'fixed_challenge' auth backend!\n")); + return ret; + } + + return ret; +} diff --git a/source4/auth/ntlm/auth_proto.h b/source4/auth/ntlm/auth_proto.h new file mode 100644 index 0000000000..572c1a4ca7 --- /dev/null +++ b/source4/auth/ntlm/auth_proto.h @@ -0,0 +1,50 @@ +#ifndef __AUTH_NTLM_AUTH_PROTO_H__ +#define __AUTH_NTLM_AUTH_PROTO_H__ + +#undef _PRINTF_ATTRIBUTE +#define _PRINTF_ATTRIBUTE(a1, a2) PRINTF_ATTRIBUTE(a1, a2) +/* This file was automatically generated by mkproto.pl. DO NOT EDIT */ + +/* this file contains prototypes for functions that are private + * to this subsystem or library. These functions should not be + * used outside this particular subsystem! */ + + +/* The following definitions come from auth/ntlm/auth.c */ + + +/*************************************************************************** + Set a fixed challenge +***************************************************************************/ +bool auth_challenge_may_be_modified(struct auth_context *auth_ctx) ; +const struct auth_operations *auth_backend_byname(const char *name); +const struct auth_critical_sizes *auth_interface_version(void); +NTSTATUS server_service_auth_init(void); + +/* The following definitions come from auth/ntlm/auth_util.c */ + +NTSTATUS auth_get_challenge_not_implemented(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, DATA_BLOB *challenge); + +/**************************************************************************** + Create an auth_usersupplied_data structure after appropriate mapping. +****************************************************************************/ +NTSTATUS map_user_info(TALLOC_CTX *mem_ctx, + const char *default_domain, + const struct auth_usersupplied_info *user_info, + struct auth_usersupplied_info **user_info_mapped); + +/**************************************************************************** + Create an auth_usersupplied_data structure after appropriate mapping. +****************************************************************************/ +NTSTATUS encrypt_user_info(TALLOC_CTX *mem_ctx, struct auth_context *auth_context, + enum auth_password_state to_state, + const struct auth_usersupplied_info *user_info_in, + const struct auth_usersupplied_info **user_info_encrypted); + +/* The following definitions come from auth/ntlm/auth_simple.c */ + +#undef _PRINTF_ATTRIBUTE +#define _PRINTF_ATTRIBUTE(a1, a2) + +#endif /* __AUTH_NTLM_AUTH_PROTO_H__ */ + diff --git a/source4/auth/ntlm/auth_sam.c b/source4/auth/ntlm/auth_sam.c new file mode 100644 index 0000000000..2c13cd963d --- /dev/null +++ b/source4/auth/ntlm/auth_sam.c @@ -0,0 +1,449 @@ +/* + Unix SMB/CIFS implementation. + Password and authentication handling + Copyright (C) Andrew Bartlett 2001-2004 + Copyright (C) Gerald Carter 2003 + Copyright (C) Stefan Metzmacher 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 3 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, see . +*/ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_netlogon.h" +#include "system/time.h" +#include "lib/ldb/include/ldb.h" +#include "util/util_ldb.h" +#include "auth/auth.h" +#include "auth/ntlm/ntlm_check.h" +#include "auth/ntlm/auth_proto.h" +#include "auth/auth_sam.h" +#include "dsdb/samdb/samdb.h" +#include "libcli/security/security.h" +#include "libcli/ldap/ldap_ndr.h" +#include "param/param.h" + +extern const char *user_attrs[]; +extern const char *domain_ref_attrs[]; + +/**************************************************************************** + Look for the specified user in the sam, return ldb result structures +****************************************************************************/ + +static NTSTATUS authsam_search_account(TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx, + const char *account_name, + const char *domain_name, + struct ldb_message ***ret_msgs, + struct ldb_message ***ret_msgs_domain_ref) +{ + struct ldb_message **msgs_tmp; + struct ldb_message **msgs; + struct ldb_message **msgs_domain_ref; + struct ldb_dn *partitions_basedn = samdb_partitions_dn(sam_ctx, mem_ctx); + + int ret; + int ret_domain; + + struct ldb_dn *domain_dn = NULL; + + if (domain_name) { + domain_dn = samdb_domain_to_dn(sam_ctx, mem_ctx, domain_name); + if (!domain_dn) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + } + + /* pull the user attributes */ + ret = gendb_search(sam_ctx, mem_ctx, domain_dn, &msgs, user_attrs, + "(&(sAMAccountName=%s)(objectclass=user))", + ldb_binary_encode_string(mem_ctx, account_name)); + if (ret == -1) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + if (ret == 0) { + DEBUG(3,("sam_search_user: Couldn't find user [%s\\%s] in samdb, under %s\n", + domain_name, account_name, ldb_dn_get_linearized(domain_dn))); + return NT_STATUS_NO_SUCH_USER; + } + + if (ret > 1) { + DEBUG(0,("Found %d records matching user [%s]\n", ret, account_name)); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + if (!domain_dn) { + struct dom_sid *domain_sid; + + domain_sid = samdb_result_sid_prefix(mem_ctx, msgs[0], "objectSid"); + if (!domain_sid) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + /* find the domain's DN */ + ret = gendb_search(sam_ctx, mem_ctx, NULL, &msgs_tmp, NULL, + "(&(objectSid=%s)(objectClass=domain))", + ldap_encode_ndr_dom_sid(mem_ctx, domain_sid)); + if (ret == -1) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + if (ret == 0) { + DEBUG(3,("check_sam_security: Couldn't find domain_sid [%s] in passdb file.\n", + dom_sid_string(mem_ctx, domain_sid))); + return NT_STATUS_NO_SUCH_USER; + } + + if (ret > 1) { + DEBUG(0,("Found %d records matching domain_sid [%s]\n", + ret, dom_sid_string(mem_ctx, domain_sid))); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + domain_dn = msgs_tmp[0]->dn; + } + + ret_domain = gendb_search(sam_ctx, mem_ctx, partitions_basedn, &msgs_domain_ref, domain_ref_attrs, + "(nCName=%s)", ldb_dn_get_linearized(domain_dn)); + if (ret_domain == -1) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + if (ret_domain == 0) { + DEBUG(3,("check_sam_security: Couldn't find domain [%s] in passdb file.\n", + ldb_dn_get_linearized(msgs_tmp[0]->dn))); + return NT_STATUS_NO_SUCH_USER; + } + + if (ret_domain > 1) { + DEBUG(0,("Found %d records matching domain [%s]\n", + ret_domain, ldb_dn_get_linearized(msgs_tmp[0]->dn))); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + *ret_msgs = msgs; + *ret_msgs_domain_ref = msgs_domain_ref; + + return NT_STATUS_OK; +} + +/**************************************************************************** + Do a specific test for an smb password being correct, given a smb_password and + the lanman and NT responses. +****************************************************************************/ +static NTSTATUS authsam_password_ok(struct auth_context *auth_context, + TALLOC_CTX *mem_ctx, + uint16_t acct_flags, + const struct samr_Password *lm_pwd, + const struct samr_Password *nt_pwd, + const struct auth_usersupplied_info *user_info, + DATA_BLOB *user_sess_key, + DATA_BLOB *lm_sess_key) +{ + NTSTATUS status; + + if (acct_flags & ACB_PWNOTREQ) { + if (lp_null_passwords(auth_context->lp_ctx)) { + DEBUG(3,("Account for user '%s' has no password and null passwords are allowed.\n", + user_info->mapped.account_name)); + return NT_STATUS_OK; + } else { + DEBUG(3,("Account for user '%s' has no password and null passwords are NOT allowed.\n", + user_info->mapped.account_name)); + return NT_STATUS_LOGON_FAILURE; + } + } + + switch (user_info->password_state) { + case AUTH_PASSWORD_PLAIN: + { + const struct auth_usersupplied_info *user_info_temp; + status = encrypt_user_info(mem_ctx, auth_context, + AUTH_PASSWORD_HASH, + user_info, &user_info_temp); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to convert plaintext password to password HASH: %s\n", nt_errstr(status))); + return status; + } + user_info = user_info_temp; + + /*fall through*/ + } + case AUTH_PASSWORD_HASH: + *lm_sess_key = data_blob(NULL, 0); + *user_sess_key = data_blob(NULL, 0); + status = hash_password_check(mem_ctx, + auth_context->lp_ctx, + user_info->password.hash.lanman, + user_info->password.hash.nt, + user_info->mapped.account_name, + lm_pwd, nt_pwd); + NT_STATUS_NOT_OK_RETURN(status); + break; + + case AUTH_PASSWORD_RESPONSE: + status = ntlm_password_check(mem_ctx, + auth_context->lp_ctx, + user_info->logon_parameters, + &auth_context->challenge.data, + &user_info->password.response.lanman, + &user_info->password.response.nt, + user_info->mapped.account_name, + user_info->client.account_name, + user_info->client.domain_name, + lm_pwd, nt_pwd, + user_sess_key, lm_sess_key); + NT_STATUS_NOT_OK_RETURN(status); + break; + } + + if (user_sess_key && user_sess_key->data) { + talloc_steal(auth_context, user_sess_key->data); + } + if (lm_sess_key && lm_sess_key->data) { + talloc_steal(auth_context, lm_sess_key->data); + } + + return NT_STATUS_OK; +} + + + +static NTSTATUS authsam_authenticate(struct auth_context *auth_context, + TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx, + struct ldb_message **msgs, + struct ldb_message **msgs_domain_ref, + const struct auth_usersupplied_info *user_info, + DATA_BLOB *user_sess_key, DATA_BLOB *lm_sess_key) +{ + struct samr_Password *lm_pwd, *nt_pwd; + NTSTATUS nt_status; + struct ldb_dn *domain_dn = samdb_result_dn(sam_ctx, mem_ctx, msgs_domain_ref[0], "nCName", NULL); + + uint16_t acct_flags = samdb_result_acct_flags(sam_ctx, mem_ctx, msgs[0], domain_dn); + + /* Quit if the account was locked out. */ + if (acct_flags & ACB_AUTOLOCK) { + DEBUG(3,("check_sam_security: Account for user %s was locked out.\n", + user_info->mapped.account_name)); + return NT_STATUS_ACCOUNT_LOCKED_OUT; + } + + /* You can only do an interactive login to normal accounts */ + if (user_info->flags & USER_INFO_INTERACTIVE_LOGON) { + if (!(acct_flags & ACB_NORMAL)) { + return NT_STATUS_NO_SUCH_USER; + } + } + + nt_status = samdb_result_passwords(mem_ctx, msgs[0], &lm_pwd, &nt_pwd); + NT_STATUS_NOT_OK_RETURN(nt_status); + + nt_status = authsam_password_ok(auth_context, mem_ctx, + acct_flags, lm_pwd, nt_pwd, + user_info, user_sess_key, lm_sess_key); + NT_STATUS_NOT_OK_RETURN(nt_status); + + nt_status = authsam_account_ok(mem_ctx, sam_ctx, + user_info->logon_parameters, + msgs[0], + msgs_domain_ref[0], + user_info->workstation_name, + user_info->mapped.account_name); + + return nt_status; +} + + + +static NTSTATUS authsam_check_password_internals(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const char *domain, + const struct auth_usersupplied_info *user_info, + struct auth_serversupplied_info **server_info) +{ + NTSTATUS nt_status; + const char *account_name = user_info->mapped.account_name; + struct ldb_message **msgs; + struct ldb_message **domain_ref_msgs; + struct ldb_context *sam_ctx; + DATA_BLOB user_sess_key, lm_sess_key; + TALLOC_CTX *tmp_ctx; + + if (!account_name || !*account_name) { + /* 'not for me' */ + return NT_STATUS_NOT_IMPLEMENTED; + } + + tmp_ctx = talloc_new(mem_ctx); + if (!tmp_ctx) { + return NT_STATUS_NO_MEMORY; + } + + sam_ctx = samdb_connect(tmp_ctx, ctx->auth_ctx->event_ctx, ctx->auth_ctx->lp_ctx, system_session(mem_ctx, ctx->auth_ctx->lp_ctx)); + if (sam_ctx == NULL) { + talloc_free(tmp_ctx); + return NT_STATUS_INVALID_SYSTEM_SERVICE; + } + + nt_status = authsam_search_account(tmp_ctx, sam_ctx, account_name, domain, &msgs, &domain_ref_msgs); + if (!NT_STATUS_IS_OK(nt_status)) { + talloc_free(tmp_ctx); + return nt_status; + } + + nt_status = authsam_authenticate(ctx->auth_ctx, tmp_ctx, sam_ctx, msgs, domain_ref_msgs, user_info, + &user_sess_key, &lm_sess_key); + if (!NT_STATUS_IS_OK(nt_status)) { + talloc_free(tmp_ctx); + return nt_status; + } + + nt_status = authsam_make_server_info(tmp_ctx, sam_ctx, lp_netbios_name(ctx->auth_ctx->lp_ctx), + msgs[0], domain_ref_msgs[0], + user_sess_key, lm_sess_key, + server_info); + if (!NT_STATUS_IS_OK(nt_status)) { + talloc_free(tmp_ctx); + return nt_status; + } + + talloc_steal(mem_ctx, *server_info); + talloc_free(tmp_ctx); + + return NT_STATUS_OK; +} + +static NTSTATUS authsam_ignoredomain_want_check(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info) +{ + if (!user_info->mapped.account_name || !*user_info->mapped.account_name) { + return NT_STATUS_NOT_IMPLEMENTED; + } + + return NT_STATUS_OK; +} + +static NTSTATUS authsam_ignoredomain_check_password(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info, + struct auth_serversupplied_info **server_info) +{ + return authsam_check_password_internals(ctx, mem_ctx, NULL, user_info, server_info); +} + +/**************************************************************************** +Check SAM security (above) but with a few extra checks. +****************************************************************************/ +static NTSTATUS authsam_want_check(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info) +{ + bool is_local_name, is_my_domain; + + if (!user_info->mapped.account_name || !*user_info->mapped.account_name) { + return NT_STATUS_NOT_IMPLEMENTED; + } + + is_local_name = lp_is_myname(ctx->auth_ctx->lp_ctx, + user_info->mapped.domain_name); + is_my_domain = lp_is_mydomain(ctx->auth_ctx->lp_ctx, + user_info->mapped.domain_name); + + /* check whether or not we service this domain/workgroup name */ + switch (lp_server_role(ctx->auth_ctx->lp_ctx)) { + case ROLE_STANDALONE: + return NT_STATUS_OK; + + case ROLE_DOMAIN_MEMBER: + if (!is_local_name) { + DEBUG(6,("authsam_check_password: %s is not one of my local names (DOMAIN_MEMBER)\n", + user_info->mapped.domain_name)); + return NT_STATUS_NOT_IMPLEMENTED; + } + return NT_STATUS_OK; + + case ROLE_DOMAIN_CONTROLLER: + if (!is_local_name && !is_my_domain) { + DEBUG(6,("authsam_check_password: %s is not one of my local names or domain name (DC)\n", + user_info->mapped.domain_name)); + return NT_STATUS_NOT_IMPLEMENTED; + } + return NT_STATUS_OK; + } + + DEBUG(6,("authsam_check_password: lp_server_role() has an undefined value\n")); + return NT_STATUS_NOT_IMPLEMENTED; +} + +/**************************************************************************** +Check SAM security (above) but with a few extra checks. +****************************************************************************/ +static NTSTATUS authsam_check_password(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info, + struct auth_serversupplied_info **server_info) +{ + const char *domain; + + /* check whether or not we service this domain/workgroup name */ + switch (lp_server_role(ctx->auth_ctx->lp_ctx)) { + case ROLE_STANDALONE: + case ROLE_DOMAIN_MEMBER: + domain = lp_netbios_name(ctx->auth_ctx->lp_ctx); + break; + + case ROLE_DOMAIN_CONTROLLER: + domain = lp_workgroup(ctx->auth_ctx->lp_ctx); + break; + + default: + return NT_STATUS_NO_SUCH_USER; + } + + return authsam_check_password_internals(ctx, mem_ctx, domain, user_info, server_info); +} + +static const struct auth_operations sam_ignoredomain_ops = { + .name = "sam_ignoredomain", + .get_challenge = auth_get_challenge_not_implemented, + .want_check = authsam_ignoredomain_want_check, + .check_password = authsam_ignoredomain_check_password +}; + +static const struct auth_operations sam_ops = { + .name = "sam", + .get_challenge = auth_get_challenge_not_implemented, + .want_check = authsam_want_check, + .check_password = authsam_check_password +}; + +_PUBLIC_ NTSTATUS auth_sam_init(void) +{ + NTSTATUS ret; + + ret = auth_register(&sam_ops); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(0,("Failed to register 'sam' auth backend!\n")); + return ret; + } + + ret = auth_register(&sam_ignoredomain_ops); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(0,("Failed to register 'sam_ignoredomain' auth backend!\n")); + return ret; + } + + return ret; +} diff --git a/source4/auth/ntlm/auth_server.c b/source4/auth/ntlm/auth_server.c new file mode 100644 index 0000000000..be5f84fe39 --- /dev/null +++ b/source4/auth/ntlm/auth_server.c @@ -0,0 +1,225 @@ +/* + Unix SMB/CIFS implementation. + Authenticate by using a remote server + Copyright (C) Andrew Bartlett 2001-2002, 2008 + Copyright (C) Jelmer Vernooij 2002 + Copyright (C) Stefan Metzmacher 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 3 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, see . +*/ + +#include "includes.h" +#include "auth/auth.h" +#include "auth/auth_proto.h" +#include "auth/credentials/credentials.h" +#include "libcli/security/security.h" +#include "librpc/gen_ndr/ndr_samr.h" +#include "libcli/smb_composite/smb_composite.h" +#include "param/param.h" +#include "libcli/resolve/resolve.h" + +/* This version of 'security=server' rewirtten from scratch for Samba4 + * libraries in 2008 */ + + +static NTSTATUS server_want_check(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info) +{ + return NT_STATUS_OK; +} +/** + * The challenge from the target server, when operating in security=server + **/ +static NTSTATUS server_get_challenge(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, DATA_BLOB *_blob) +{ + struct smb_composite_connect io; + struct smbcli_options smb_options; + const char **host_list; + NTSTATUS status; + + /* Make a connection to the target server, found by 'password server' in smb.conf */ + + lp_smbcli_options(ctx->auth_ctx->lp_ctx, &smb_options); + + /* Make a negprot, WITHOUT SPNEGO, so we get a challenge nice an easy */ + io.in.options.use_spnego = false; + + /* Hope we don't get * (the default), as this won't work... */ + host_list = lp_passwordserver(ctx->auth_ctx->lp_ctx); + if (!host_list) { + return NT_STATUS_INTERNAL_ERROR; + } + io.in.dest_host = host_list[0]; + if (strequal(io.in.dest_host, "*")) { + return NT_STATUS_INTERNAL_ERROR; + } + io.in.dest_ports = lp_smb_ports(ctx->auth_ctx->lp_ctx); + + io.in.called_name = strupper_talloc(mem_ctx, io.in.dest_host); + + /* We don't want to get as far as the session setup */ + io.in.credentials = NULL; + io.in.service = NULL; + + io.in.workgroup = ""; /* only used with SPNEGO, disabled above */ + + io.in.options = smb_options; + + status = smb_composite_connect(&io, mem_ctx, lp_resolve_context(ctx->auth_ctx->lp_ctx), + ctx->auth_ctx->event_ctx); + if (!NT_STATUS_IS_OK(status)) { + *_blob = io.out.tree->session->transport->negotiate.secblob; + ctx->private_data = talloc_steal(ctx, io.out.tree->session); + } + return NT_STATUS_OK; +} + +/** + * Return an error based on username + * + * This function allows the testing of obsure errors, as well as the generation + * of NT_STATUS -> DOS error mapping tables. + * + * This module is of no value to end-users. + * + * The password is ignored. + * + * @return An NTSTATUS value based on the username + **/ + +static NTSTATUS server_check_password(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info, + struct auth_serversupplied_info **_server_info) +{ + NTSTATUS nt_status; + struct auth_serversupplied_info *server_info; + struct cli_credentials *creds; + const char *user; + struct smb_composite_sesssetup session_setup; + + struct smbcli_session *session = talloc_get_type(ctx->private_data, struct smbcli_session); + + creds = cli_credentials_init(mem_ctx); + + NT_STATUS_HAVE_NO_MEMORY(creds); + + cli_credentials_set_username(creds, user_info->client.account_name, CRED_SPECIFIED); + cli_credentials_set_domain(creds, user_info->client.domain_name, CRED_SPECIFIED); + + switch (user_info->password_state) { + case AUTH_PASSWORD_PLAIN: + cli_credentials_set_password(creds, user_info->password.plaintext, + CRED_SPECIFIED); + break; + case AUTH_PASSWORD_HASH: + cli_credentials_set_nt_hash(creds, user_info->password.hash.nt, + CRED_SPECIFIED); + break; + + case AUTH_PASSWORD_RESPONSE: + cli_credentials_set_ntlm_response(creds, &user_info->password.response.lanman, &user_info->password.response.nt, CRED_SPECIFIED); + break; + } + + session_setup.in.sesskey = session->transport->negotiate.sesskey; + session_setup.in.capabilities = session->transport->negotiate.capabilities; + + session_setup.in.credentials = creds; + session_setup.in.workgroup = ""; /* Only used with SPNEGO, which we are not doing */ + + /* Check password with remove server - this should be async some day */ + nt_status = smb_composite_sesssetup(session, &session_setup); + + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + + server_info = talloc(mem_ctx, struct auth_serversupplied_info); + NT_STATUS_HAVE_NO_MEMORY(server_info); + + server_info->account_sid = dom_sid_parse_talloc(server_info, SID_NT_ANONYMOUS); + NT_STATUS_HAVE_NO_MEMORY(server_info->account_sid); + + /* is this correct? */ + server_info->primary_group_sid = dom_sid_parse_talloc(server_info, SID_BUILTIN_GUESTS); + NT_STATUS_HAVE_NO_MEMORY(server_info->primary_group_sid); + + server_info->n_domain_groups = 0; + server_info->domain_groups = NULL; + + /* annoying, but the Anonymous really does have a session key, + and it is all zeros! */ + server_info->user_session_key = data_blob(NULL, 0); + server_info->lm_session_key = data_blob(NULL, 0); + + server_info->account_name = talloc_strdup(server_info, user_info->client.account_name); + NT_STATUS_HAVE_NO_MEMORY(server_info->account_name); + + server_info->domain_name = talloc_strdup(server_info, user_info->client.domain_name); + NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name); + + server_info->full_name = NULL; + + server_info->logon_script = talloc_strdup(server_info, ""); + NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script); + + server_info->profile_path = talloc_strdup(server_info, ""); + NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path); + + server_info->home_directory = talloc_strdup(server_info, ""); + NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory); + + server_info->home_drive = talloc_strdup(server_info, ""); + NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive); + + server_info->last_logon = 0; + server_info->last_logoff = 0; + server_info->acct_expiry = 0; + server_info->last_password_change = 0; + server_info->allow_password_change = 0; + server_info->force_password_change = 0; + + server_info->logon_count = 0; + server_info->bad_password_count = 0; + + server_info->acct_flags = ACB_NORMAL; + + server_info->authenticated = false; + + *_server_info = server_info; + + return nt_status; +} + +static const struct auth_operations server_auth_ops = { + .name = "server", + .get_challenge = server_get_challenge, + .want_check = server_want_check, + .check_password = server_check_password +}; + +_PUBLIC_ NTSTATUS auth_server_init(void) +{ + NTSTATUS ret; + + ret = auth_register(&server_auth_ops); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(0,("Failed to register 'server' auth backend!\n")); + return ret; + } + + return ret; +} diff --git a/source4/auth/ntlm/auth_simple.c b/source4/auth/ntlm/auth_simple.c new file mode 100644 index 0000000000..e7039c3657 --- /dev/null +++ b/source4/auth/ntlm/auth_simple.c @@ -0,0 +1,103 @@ +/* + Unix SMB/CIFS implementation. + + auth functions + + Copyright (C) Simo Sorce 2005 + Copyright (C) Andrew Tridgell 2005 + Copyright (C) Andrew Bartlett 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 3 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, see . +*/ + +#include "includes.h" +#include "auth/auth.h" +#include "lib/events/events.h" +#include "param/param.h" +#include "auth/session_proto.h" + +/* + It's allowed to pass NULL as session_info, + when the caller doesn't need a session_info +*/ +_PUBLIC_ NTSTATUS authenticate_username_pw(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct messaging_context *msg, + struct loadparm_context *lp_ctx, + const char *nt4_domain, + const char *nt4_username, + const char *password, + struct auth_session_info **session_info) +{ + struct auth_context *auth_context; + struct auth_usersupplied_info *user_info; + struct auth_serversupplied_info *server_info; + NTSTATUS nt_status; + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + + if (!tmp_ctx) { + return NT_STATUS_NO_MEMORY; + } + + nt_status = auth_context_create(tmp_ctx, + ev, msg, + lp_ctx, + &auth_context); + if (!NT_STATUS_IS_OK(nt_status)) { + talloc_free(tmp_ctx); + return nt_status; + } + + user_info = talloc(tmp_ctx, struct auth_usersupplied_info); + if (!user_info) { + talloc_free(tmp_ctx); + return NT_STATUS_NO_MEMORY; + } + + user_info->mapped_state = true; + user_info->client.account_name = nt4_username; + user_info->mapped.account_name = nt4_username; + user_info->client.domain_name = nt4_domain; + user_info->mapped.domain_name = nt4_domain; + + user_info->workstation_name = NULL; + + user_info->remote_host = NULL; + + user_info->password_state = AUTH_PASSWORD_PLAIN; + user_info->password.plaintext = talloc_strdup(user_info, password); + + user_info->flags = USER_INFO_CASE_INSENSITIVE_USERNAME | + USER_INFO_DONT_CHECK_UNIX_ACCOUNT; + + user_info->logon_parameters = 0; + + nt_status = auth_check_password(auth_context, tmp_ctx, user_info, &server_info); + if (!NT_STATUS_IS_OK(nt_status)) { + talloc_free(tmp_ctx); + return nt_status; + } + + if (session_info) { + nt_status = auth_generate_session_info(tmp_ctx, ev, lp_ctx, server_info, session_info); + + if (NT_STATUS_IS_OK(nt_status)) { + talloc_steal(mem_ctx, *session_info); + } + } + + talloc_free(tmp_ctx); + return nt_status; +} + diff --git a/source4/auth/ntlm/auth_unix.c b/source4/auth/ntlm/auth_unix.c new file mode 100644 index 0000000000..a417107025 --- /dev/null +++ b/source4/auth/ntlm/auth_unix.c @@ -0,0 +1,844 @@ +/* + Unix SMB/CIFS implementation. + Password and authentication handling + Copyright (C) Andrew Bartlett 2001 + Copyright (C) Jeremy Allison 2001 + Copyright (C) Simo Sorce 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 3 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, see . +*/ + +#include "includes.h" +#include "auth/auth.h" +#include "auth/auth_proto.h" +#include "system/passwd.h" /* needed by some systems for struct passwd */ +#include "lib/socket/socket.h" +#include "auth/pam_errors.h" +#include "param/param.h" + +/* TODO: look at how to best fill in parms retrieveing a struct passwd info + * except in case USER_INFO_DONT_CHECK_UNIX_ACCOUNT is set + */ +static NTSTATUS authunix_make_server_info(TALLOC_CTX *mem_ctx, + const char *netbios_name, + const struct auth_usersupplied_info *user_info, + struct passwd *pwd, + struct auth_serversupplied_info **_server_info) +{ + struct auth_serversupplied_info *server_info; + NTSTATUS status; + + /* This is a real, real hack */ + if (pwd->pw_uid == 0) { + status = auth_system_server_info(mem_ctx, netbios_name, &server_info); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + server_info->account_name = talloc_steal(server_info, pwd->pw_name); + NT_STATUS_HAVE_NO_MEMORY(server_info->account_name); + + server_info->domain_name = talloc_strdup(server_info, "unix"); + NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name); + } else { + server_info = talloc(mem_ctx, struct auth_serversupplied_info); + NT_STATUS_HAVE_NO_MEMORY(server_info); + + server_info->authenticated = true; + + server_info->account_name = talloc_steal(server_info, pwd->pw_name); + NT_STATUS_HAVE_NO_MEMORY(server_info->account_name); + + server_info->domain_name = talloc_strdup(server_info, "unix"); + NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name); + + /* This isn't in any way correct.. */ + server_info->account_sid = NULL; + server_info->primary_group_sid = NULL; + server_info->n_domain_groups = 0; + server_info->domain_groups = NULL; + } + server_info->user_session_key = data_blob(NULL,0); + server_info->lm_session_key = data_blob(NULL,0); + + server_info->full_name = talloc_steal(server_info, pwd->pw_gecos); + NT_STATUS_HAVE_NO_MEMORY(server_info->full_name); + server_info->logon_script = talloc_strdup(server_info, ""); + NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script); + server_info->profile_path = talloc_strdup(server_info, ""); + NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path); + server_info->home_directory = talloc_strdup(server_info, ""); + NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory); + server_info->home_drive = talloc_strdup(server_info, ""); + NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive); + + server_info->last_logon = 0; + server_info->last_logoff = 0; + server_info->acct_expiry = 0; + server_info->last_password_change = 0; + server_info->allow_password_change = 0; + server_info->force_password_change = 0; + server_info->logon_count = 0; + server_info->bad_password_count = 0; + server_info->acct_flags = 0; + + *_server_info = server_info; + + return NT_STATUS_OK; +} + +static NTSTATUS talloc_getpwnam(TALLOC_CTX *ctx, const char *username, struct passwd **pws) +{ + struct passwd *ret; + struct passwd *from; + + *pws = NULL; + + ret = talloc(ctx, struct passwd); + NT_STATUS_HAVE_NO_MEMORY(ret); + + from = getpwnam(username); + if (!from) { + return NT_STATUS_NO_SUCH_USER; + } + + ret->pw_name = talloc_strdup(ctx, from->pw_name); + NT_STATUS_HAVE_NO_MEMORY(ret->pw_name); + + ret->pw_passwd = talloc_strdup(ctx, from->pw_passwd); + NT_STATUS_HAVE_NO_MEMORY(ret->pw_passwd); + + ret->pw_uid = from->pw_uid; + ret->pw_gid = from->pw_gid; + ret->pw_gecos = talloc_strdup(ctx, from->pw_gecos); + NT_STATUS_HAVE_NO_MEMORY(ret->pw_gecos); + + ret->pw_dir = talloc_strdup(ctx, from->pw_dir); + NT_STATUS_HAVE_NO_MEMORY(ret->pw_dir); + + ret->pw_shell = talloc_strdup(ctx, from->pw_shell); + NT_STATUS_HAVE_NO_MEMORY(ret->pw_shell); + + *pws = ret; + + return NT_STATUS_OK; +} + + +#ifdef HAVE_SECURITY_PAM_APPL_H +#include + +struct smb_pam_user_info { + const char *account_name; + const char *plaintext_password; +}; + +#define COPY_STRING(s) (s) ? strdup(s) : NULL + +/* + * Check user password + * Currently it uses PAM only and fails on systems without PAM + * Samba3 code located in pass_check.c is to ugly to be used directly it will + * need major rework that's why pass_check.c is still there. +*/ + +static int smb_pam_conv(int num_msg, const struct pam_message **msg, + struct pam_response **reply, void *appdata_ptr) +{ + struct smb_pam_user_info *info = (struct smb_pam_user_info *)appdata_ptr; + int num; + + if (num_msg <= 0) { + *reply = NULL; + return PAM_CONV_ERR; + } + + /* + * Apparantly HPUX has a buggy PAM that doesn't support the + * data pointer. Fail if this is the case. JRA. + */ + + if (info == NULL) { + *reply = NULL; + return PAM_CONV_ERR; + } + + /* + * PAM frees memory in reply messages by itself + * so use malloc instead of talloc here. + */ + *reply = malloc_array_p(struct pam_response, num_msg); + if (*reply == NULL) { + return PAM_CONV_ERR; + } + + for (num = 0; num < num_msg; num++) { + switch (msg[num]->msg_style) { + case PAM_PROMPT_ECHO_ON: + (*reply)[num].resp_retcode = PAM_SUCCESS; + (*reply)[num].resp = COPY_STRING(info->account_name); + break; + + case PAM_PROMPT_ECHO_OFF: + (*reply)[num].resp_retcode = PAM_SUCCESS; + (*reply)[num].resp = COPY_STRING(info->plaintext_password); + break; + + case PAM_TEXT_INFO: + (*reply)[num].resp_retcode = PAM_SUCCESS; + (*reply)[num].resp = NULL; + DEBUG(4,("PAM Info message in conversation function: %s\n", (msg[num]->msg))); + break; + + case PAM_ERROR_MSG: + (*reply)[num].resp_retcode = PAM_SUCCESS; + (*reply)[num].resp = NULL; + DEBUG(4,("PAM Error message in conversation function: %s\n", (msg[num]->msg))); + break; + + default: + while (num > 0) { + SAFE_FREE((*reply)[num-1].resp); + num--; + } + SAFE_FREE(*reply); + *reply = NULL; + DEBUG(1,("Error: PAM subsystme sent an UNKNOWN message type to the conversation function!\n")); + return PAM_CONV_ERR; + } + } + + return PAM_SUCCESS; +} + +/* + * Start PAM authentication for specified account + */ + +static NTSTATUS smb_pam_start(pam_handle_t **pamh, const char *account_name, const char *remote_host, struct pam_conv *pconv) +{ + int pam_error; + + if (account_name == NULL || remote_host == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + DEBUG(4,("smb_pam_start: PAM: Init user: %s\n", account_name)); + + pam_error = pam_start("samba", account_name, pconv, pamh); + if (pam_error != PAM_SUCCESS) { + /* no valid pamh here, can we reliably call pam_strerror ? */ + DEBUG(4,("smb_pam_start: pam_start failed!\n")); + return NT_STATUS_UNSUCCESSFUL; + } + +#ifdef PAM_RHOST + DEBUG(4,("smb_pam_start: PAM: setting rhost to: %s\n", remote_host)); + pam_error = pam_set_item(*pamh, PAM_RHOST, remote_host); + if (pam_error != PAM_SUCCESS) { + NTSTATUS nt_status; + + DEBUG(4,("smb_pam_start: setting rhost failed with error: %s\n", + pam_strerror(*pamh, pam_error))); + nt_status = pam_to_nt_status(pam_error); + + pam_error = pam_end(*pamh, 0); + if (pam_error != PAM_SUCCESS) { + /* no vaild pamh here, can we reliably call pam_strerror ? */ + DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n", + pam_error)); + return pam_to_nt_status(pam_error); + } + return nt_status; + } +#endif +#ifdef PAM_TTY + DEBUG(4,("smb_pam_start: PAM: setting tty\n")); + pam_error = pam_set_item(*pamh, PAM_TTY, "samba"); + if (pam_error != PAM_SUCCESS) { + NTSTATUS nt_status; + + DEBUG(4,("smb_pam_start: setting tty failed with error: %s\n", + pam_strerror(*pamh, pam_error))); + nt_status = pam_to_nt_status(pam_error); + + pam_error = pam_end(*pamh, 0); + if (pam_error != PAM_SUCCESS) { + /* no vaild pamh here, can we reliably call pam_strerror ? */ + DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n", + pam_error)); + return pam_to_nt_status(pam_error); + } + return nt_status; + } +#endif + DEBUG(4,("smb_pam_start: PAM: Init passed for user: %s\n", account_name)); + + return NT_STATUS_OK; +} + +static NTSTATUS smb_pam_end(pam_handle_t *pamh) +{ + int pam_error; + + if (pamh != NULL) { + pam_error = pam_end(pamh, 0); + if (pam_error != PAM_SUCCESS) { + /* no vaild pamh here, can we reliably call pam_strerror ? */ + DEBUG(4,("smb_pam_end: clean up failed, pam_end gave error %d.\n", + pam_error)); + return pam_to_nt_status(pam_error); + } + return NT_STATUS_OK; + } + + DEBUG(2,("smb_pam_end: pamh is NULL, PAM not initialized ?\n")); + return NT_STATUS_UNSUCCESSFUL; +} + +/* + * PAM Authentication Handler + */ +static NTSTATUS smb_pam_auth(pam_handle_t *pamh, bool allow_null_passwords, const char *user) +{ + int pam_error; + + /* + * To enable debugging set in /etc/pam.d/samba: + * auth required /lib/security/pam_pwdb.so nullok shadow audit + */ + + DEBUG(4,("smb_pam_auth: PAM: Authenticate User: %s\n", user)); + + pam_error = pam_authenticate(pamh, PAM_SILENT | allow_null_passwords ? 0 : PAM_DISALLOW_NULL_AUTHTOK); + switch( pam_error ){ + case PAM_AUTH_ERR: + DEBUG(2, ("smb_pam_auth: PAM: Authentication Error for user %s\n", user)); + break; + case PAM_CRED_INSUFFICIENT: + DEBUG(2, ("smb_pam_auth: PAM: Insufficient Credentials for user %s\n", user)); + break; + case PAM_AUTHINFO_UNAVAIL: + DEBUG(2, ("smb_pam_auth: PAM: Authentication Information Unavailable for user %s\n", user)); + break; + case PAM_USER_UNKNOWN: + DEBUG(2, ("smb_pam_auth: PAM: Username %s NOT known to Authentication system\n", user)); + break; + case PAM_MAXTRIES: + DEBUG(2, ("smb_pam_auth: PAM: One or more authentication modules reports user limit for user %s exceeeded\n", user)); + break; + case PAM_ABORT: + DEBUG(0, ("smb_pam_auth: PAM: One or more PAM modules failed to load for user %s\n", user)); + break; + case PAM_SUCCESS: + DEBUG(4, ("smb_pam_auth: PAM: User %s Authenticated OK\n", user)); + break; + default: + DEBUG(0, ("smb_pam_auth: PAM: UNKNOWN ERROR while authenticating user %s\n", user)); + break; + } + + return pam_to_nt_status(pam_error); +} + +/* + * PAM Account Handler + */ +static NTSTATUS smb_pam_account(pam_handle_t *pamh, const char * user) +{ + int pam_error; + + DEBUG(4,("smb_pam_account: PAM: Account Management for User: %s\n", user)); + + pam_error = pam_acct_mgmt(pamh, PAM_SILENT); /* Is user account enabled? */ + switch( pam_error ) { + case PAM_AUTHTOK_EXPIRED: + DEBUG(2, ("smb_pam_account: PAM: User %s is valid but password is expired\n", user)); + break; + case PAM_ACCT_EXPIRED: + DEBUG(2, ("smb_pam_account: PAM: User %s no longer permitted to access system\n", user)); + break; + case PAM_AUTH_ERR: + DEBUG(2, ("smb_pam_account: PAM: There was an authentication error for user %s\n", user)); + break; + case PAM_PERM_DENIED: + DEBUG(0, ("smb_pam_account: PAM: User %s is NOT permitted to access system at this time\n", user)); + break; + case PAM_USER_UNKNOWN: + DEBUG(0, ("smb_pam_account: PAM: User \"%s\" is NOT known to account management\n", user)); + break; + case PAM_SUCCESS: + DEBUG(4, ("smb_pam_account: PAM: Account OK for User: %s\n", user)); + break; + default: + DEBUG(0, ("smb_pam_account: PAM: UNKNOWN PAM ERROR (%d) during Account Management for User: %s\n", pam_error, user)); + break; + } + + return pam_to_nt_status(pam_error); +} + +/* + * PAM Credential Setting + */ + +static NTSTATUS smb_pam_setcred(pam_handle_t *pamh, const char * user) +{ + int pam_error; + + /* + * This will allow samba to aquire a kerberos token. And, when + * exporting an AFS cell, be able to /write/ to this cell. + */ + + DEBUG(4,("PAM: Account Management SetCredentials for User: %s\n", user)); + + pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED|PAM_SILENT)); + switch( pam_error ) { + case PAM_CRED_UNAVAIL: + DEBUG(0, ("smb_pam_setcred: PAM: Credentials not found for user:%s\n", user )); + break; + case PAM_CRED_EXPIRED: + DEBUG(0, ("smb_pam_setcred: PAM: Credentials for user: \"%s\" EXPIRED!\n", user )); + break; + case PAM_USER_UNKNOWN: + DEBUG(0, ("smb_pam_setcred: PAM: User: \"%s\" is NOT known so can not set credentials!\n", user )); + break; + case PAM_CRED_ERR: + DEBUG(0, ("smb_pam_setcred: PAM: Unknown setcredentials error - unable to set credentials for %s\n", user )); + break; + case PAM_SUCCESS: + DEBUG(4, ("smb_pam_setcred: PAM: SetCredentials OK for User: %s\n", user)); + break; + default: + DEBUG(0, ("smb_pam_setcred: PAM: UNKNOWN PAM ERROR (%d) during SetCredentials for User: %s\n", pam_error, user)); + break; + } + + return pam_to_nt_status(pam_error); +} + +static NTSTATUS check_unix_password(TALLOC_CTX *ctx, struct loadparm_context *lp_ctx, + const struct auth_usersupplied_info *user_info, struct passwd **pws) +{ + struct smb_pam_user_info *info; + struct pam_conv *pamconv; + pam_handle_t *pamh; + NTSTATUS nt_status; + + info = talloc(ctx, struct smb_pam_user_info); + if (info == NULL) { + return NT_STATUS_NO_MEMORY; + } + + info->account_name = user_info->mapped.account_name; + info->plaintext_password = user_info->password.plaintext; + + pamconv = talloc(ctx, struct pam_conv); + if (pamconv == NULL) { + return NT_STATUS_NO_MEMORY; + } + + pamconv->conv = smb_pam_conv; + pamconv->appdata_ptr = (void *)info; + + /* TODO: + * check for user_info->flags & USER_INFO_CASE_INSENSITIVE_USERNAME + * if true set up a crack name routine. + */ + + nt_status = smb_pam_start(&pamh, user_info->mapped.account_name, user_info->remote_host ? user_info->remote_host->addr : NULL, pamconv); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + + nt_status = smb_pam_auth(pamh, lp_null_passwords(lp_ctx), user_info->mapped.account_name); + if (!NT_STATUS_IS_OK(nt_status)) { + smb_pam_end(pamh); + return nt_status; + } + + if ( ! (user_info->flags & USER_INFO_DONT_CHECK_UNIX_ACCOUNT)) { + + nt_status = smb_pam_account(pamh, user_info->mapped.account_name); + if (!NT_STATUS_IS_OK(nt_status)) { + smb_pam_end(pamh); + return nt_status; + } + + nt_status = smb_pam_setcred(pamh, user_info->mapped.account_name); + if (!NT_STATUS_IS_OK(nt_status)) { + smb_pam_end(pamh); + return nt_status; + } + } + + smb_pam_end(pamh); + + nt_status = talloc_getpwnam(ctx, user_info->mapped.account_name, pws); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + + return NT_STATUS_OK; +} + +#else + +/**************************************************************************** +core of password checking routine +****************************************************************************/ +static NTSTATUS password_check(const char *username, const char *password, + const char *crypted, const char *salt) +{ + bool ret; + +#ifdef WITH_AFS + if (afs_auth(username, password)) + return NT_STATUS_OK; +#endif /* WITH_AFS */ + +#ifdef WITH_DFS + if (dfs_auth(username, password)) + return NT_STATUS_OK; +#endif /* WITH_DFS */ + +#ifdef OSF1_ENH_SEC + + ret = (strcmp(osf1_bigcrypt(password, salt), crypted) == 0); + + if (!ret) { + DEBUG(2, + ("OSF1_ENH_SEC failed. Trying normal crypt.\n")); + ret = (strcmp((char *)crypt(password, salt), crypted) == 0); + } + if (ret) { + return NT_STATUS_OK; + } else { + return NT_STATUS_WRONG_PASSWORD; + } + +#endif /* OSF1_ENH_SEC */ + +#ifdef ULTRIX_AUTH + ret = (strcmp((char *)crypt16(password, salt), crypted) == 0); + if (ret) { + return NT_STATUS_OK; + } else { + return NT_STATUS_WRONG_PASSWORD; + } + +#endif /* ULTRIX_AUTH */ + +#ifdef LINUX_BIGCRYPT + ret = (linux_bigcrypt(password, salt, crypted)); + if (ret) { + return NT_STATUS_OK; + } else { + return NT_STATUS_WRONG_PASSWORD; + } +#endif /* LINUX_BIGCRYPT */ + +#if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS) + + /* + * Some systems have bigcrypt in the C library but might not + * actually use it for the password hashes (HPUX 10.20) is + * a noteable example. So we try bigcrypt first, followed + * by crypt. + */ + + if (strcmp(bigcrypt(password, salt), crypted) == 0) + return NT_STATUS_OK; + else + ret = (strcmp((char *)crypt(password, salt), crypted) == 0); + if (ret) { + return NT_STATUS_OK; + } else { + return NT_STATUS_WRONG_PASSWORD; + } +#else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */ + +#ifdef HAVE_BIGCRYPT + ret = (strcmp(bigcrypt(password, salt), crypted) == 0); + if (ret) { + return NT_STATUS_OK; + } else { + return NT_STATUS_WRONG_PASSWORD; + } +#endif /* HAVE_BIGCRYPT */ + +#ifndef HAVE_CRYPT + DEBUG(1, ("Warning - no crypt available\n")); + return NT_STATUS_LOGON_FAILURE; +#else /* HAVE_CRYPT */ + ret = (strcmp((char *)crypt(password, salt), crypted) == 0); + if (ret) { + return NT_STATUS_OK; + } else { + return NT_STATUS_WRONG_PASSWORD; + } +#endif /* HAVE_CRYPT */ +#endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */ +} + +static NTSTATUS check_unix_password(TALLOC_CTX *ctx, struct loadparm_context *lp_ctx, + const struct auth_usersupplied_info *user_info, struct passwd **ret_passwd) +{ + char *username; + char *password; + char *pwcopy; + char *salt; + char *crypted; + struct passwd *pws; + NTSTATUS nt_status; + int level = lp_passwordlevel(lp_ctx); + + *ret_passwd = NULL; + + username = talloc_strdup(ctx, user_info->mapped.account_name); + password = talloc_strdup(ctx, user_info->password.plaintext); + + nt_status = talloc_getpwnam(ctx, username, &pws); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + + crypted = pws->pw_passwd; + salt = pws->pw_passwd; + +#ifdef HAVE_GETSPNAM + { + struct spwd *spass; + + /* many shadow systems require you to be root to get + the password, in most cases this should already be + the case when this function is called, except + perhaps for IPC password changing requests */ + + spass = getspnam(pws->pw_name); + if (spass && spass->sp_pwdp) { + crypted = talloc_strdup(ctx, spass->sp_pwdp); + NT_STATUS_HAVE_NO_MEMORY(crypted); + salt = talloc_strdup(ctx, spass->sp_pwdp); + NT_STATUS_HAVE_NO_MEMORY(salt); + } + } +#elif defined(IA_UINFO) + { + char *ia_password; + /* Need to get password with SVR4.2's ia_ functions + instead of get{sp,pw}ent functions. Required by + UnixWare 2.x, tested on version + 2.1. (tangent@cyberport.com) */ + uinfo_t uinfo; + if (ia_openinfo(pws->pw_name, &uinfo) != -1) { + ia_get_logpwd(uinfo, &ia_password); + crypted = talloc_strdup(ctx, ia_password); + NT_STATUS_HAVE_NO_MEMORY(crypted); + } + } +#endif + +#ifdef HAVE_GETPRPWNAM + { + struct pr_passwd *pr_pw = getprpwnam(pws->pw_name); + if (pr_pw && pr_pw->ufld.fd_encrypt) { + crypted = talloc_strdup(ctx, pr_pw->ufld.fd_encrypt); + NT_STATUS_HAVE_NO_MEMORY(crypted); + } + } +#endif + +#ifdef HAVE_GETPWANAM + { + struct passwd_adjunct *pwret; + pwret = getpwanam(s); + if (pwret && pwret->pwa_passwd) { + crypted = talloc_strdup(ctx, pwret->pwa_passwd); + NT_STATUS_HAVE_NO_MEMORY(crypted); + } + } +#endif + +#ifdef OSF1_ENH_SEC + { + struct pr_passwd *mypasswd; + DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n", username)); + mypasswd = getprpwnam(username); + if (mypasswd) { + username = talloc_strdup(ctx, mypasswd->ufld.fd_name); + NT_STATUS_HAVE_NO_MEMORY(username); + crypted = talloc_strdup(ctx, mypasswd->ufld.fd_encrypt); + NT_STATUS_HAVE_NO_MEMORY(crypted); + } else { + DEBUG(5,("OSF1_ENH_SEC: No entry for user %s in protected database !\n", username)); + } + } +#endif + +#ifdef ULTRIX_AUTH + { + AUTHORIZATION *ap = getauthuid(pws->pw_uid); + if (ap) { + crypted = talloc_strdup(ctx, ap->a_password); + endauthent(); + NT_STATUS_HAVE_NO_MEMORY(crypted); + } + } +#endif + +#if defined(HAVE_TRUNCATED_SALT) + /* crypt on some platforms (HPUX in particular) + won't work with more than 2 salt characters. */ + salt[2] = 0; +#endif + + if (crypted[0] == '\0') { + if (!lp_null_passwords(lp_ctx)) { + DEBUG(2, ("Disallowing %s with null password\n", username)); + return NT_STATUS_LOGON_FAILURE; + } + if (password == NULL) { + DEBUG(3, ("Allowing access to %s with null password\n", username)); + *ret_passwd = pws; + return NT_STATUS_OK; + } + } + + /* try it as it came to us */ + nt_status = password_check(username, password, crypted, salt); + if (NT_STATUS_IS_OK(nt_status)) { + *ret_passwd = pws; + return nt_status; + } + else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) { + /* No point continuing if its not the password thats to blame (ie PAM disabled). */ + return nt_status; + } + + if ( user_info->flags | USER_INFO_CASE_INSENSITIVE_PASSWORD) { + return nt_status; + } + + /* if the password was given to us with mixed case then we don't + * need to proceed as we know it hasn't been case modified by the + * client */ + if (strhasupper(password) && strhaslower(password)) { + return nt_status; + } + + /* make a copy of it */ + pwcopy = talloc_strdup(ctx, password); + if (!pwcopy) + return NT_STATUS_NO_MEMORY; + + /* try all lowercase if it's currently all uppercase */ + if (strhasupper(pwcopy)) { + strlower(pwcopy); + nt_status = password_check(username, pwcopy, crypted, salt); + if NT_STATUS_IS_OK(nt_status) { + *ret_passwd = pws; + return nt_status; + } + } + + /* give up? */ + if (level < 1) { + return NT_STATUS_WRONG_PASSWORD; + } + + /* last chance - all combinations of up to level chars upper! */ + strlower(pwcopy); + +#if 0 + if (NT_STATUS_IS_OK(nt_status = string_combinations(pwcopy, password_check, level))) { + *ret_passwd = pws; + return nt_status; + } +#endif + return NT_STATUS_WRONG_PASSWORD; +} + +#endif + +/** Check a plaintext username/password + * + **/ + +static NTSTATUS authunix_want_check(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info) +{ + if (!user_info->mapped.account_name || !*user_info->mapped.account_name) { + return NT_STATUS_NOT_IMPLEMENTED; + } + + return NT_STATUS_OK; +} + +static NTSTATUS authunix_check_password(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info, + struct auth_serversupplied_info **server_info) +{ + TALLOC_CTX *check_ctx; + NTSTATUS nt_status; + struct passwd *pwd; + + if (user_info->password_state != AUTH_PASSWORD_PLAIN) { + return NT_STATUS_INVALID_PARAMETER; + } + + check_ctx = talloc_named_const(mem_ctx, 0, "check_unix_password"); + if (check_ctx == NULL) { + return NT_STATUS_NO_MEMORY; + } + + nt_status = check_unix_password(check_ctx, ctx->auth_ctx->lp_ctx, user_info, &pwd); + if (!NT_STATUS_IS_OK(nt_status)) { + talloc_free(check_ctx); + return nt_status; + } + + nt_status = authunix_make_server_info(mem_ctx, lp_netbios_name(ctx->auth_ctx->lp_ctx), + user_info, pwd, server_info); + if (!NT_STATUS_IS_OK(nt_status)) { + talloc_free(check_ctx); + return nt_status; + } + + talloc_free(check_ctx); + return NT_STATUS_OK; +} + +static const struct auth_operations unix_ops = { + .name = "unix", + .get_challenge = auth_get_challenge_not_implemented, + .want_check = authunix_want_check, + .check_password = authunix_check_password +}; + +_PUBLIC_ NTSTATUS auth_unix_init(void) +{ + NTSTATUS ret; + + ret = auth_register(&unix_ops); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(0,("Failed to register unix auth backend!\n")); + return ret; + } + + return ret; +} diff --git a/source4/auth/ntlm/auth_util.c b/source4/auth/ntlm/auth_util.c new file mode 100644 index 0000000000..1d86b858cf --- /dev/null +++ b/source4/auth/ntlm/auth_util.c @@ -0,0 +1,260 @@ +/* + Unix SMB/CIFS implementation. + Authentication utility functions + Copyright (C) Andrew Tridgell 1992-1998 + Copyright (C) Andrew Bartlett 2001 + Copyright (C) Jeremy Allison 2000-2001 + Copyright (C) Rafal Szczesniak 2002 + Copyright (C) Stefan Metzmacher 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 3 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, see . +*/ + +#include "includes.h" +#include "auth/auth.h" +#include "libcli/security/security.h" +#include "libcli/auth/libcli_auth.h" +#include "dsdb/samdb/samdb.h" +#include "auth/credentials/credentials.h" +#include "param/param.h" + +/* this default function can be used by mostly all backends + * which don't want to set a challenge + */ +NTSTATUS auth_get_challenge_not_implemented(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, DATA_BLOB *challenge) +{ + /* we don't want to set a challenge */ + return NT_STATUS_NOT_IMPLEMENTED; +} + +/**************************************************************************** + Create an auth_usersupplied_data structure after appropriate mapping. +****************************************************************************/ + +NTSTATUS map_user_info(TALLOC_CTX *mem_ctx, + const char *default_domain, + const struct auth_usersupplied_info *user_info, + struct auth_usersupplied_info **user_info_mapped) +{ + const char *domain; + char *account_name; + char *d; + DEBUG(5,("map_user_info: Mapping user [%s]\\[%s] from workstation [%s]\n", + user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name)); + + account_name = talloc_strdup(mem_ctx, user_info->client.account_name); + if (!account_name) { + return NT_STATUS_NO_MEMORY; + } + + /* don't allow "" as a domain, fixes a Win9X bug + where it doesn't supply a domain for logon script + 'net use' commands. */ + + /* Split user@realm names into user and realm components. This is TODO to fix with proper userprincipalname support */ + if (user_info->client.domain_name && *user_info->client.domain_name) { + domain = user_info->client.domain_name; + } else if (strchr_m(user_info->client.account_name, '@')) { + d = strchr_m(account_name, '@'); + if (!d) { + return NT_STATUS_INTERNAL_ERROR; + } + d[0] = '\0'; + d++; + domain = d; + } else { + domain = default_domain; + } + + *user_info_mapped = talloc(mem_ctx, struct auth_usersupplied_info); + if (!*user_info_mapped) { + return NT_STATUS_NO_MEMORY; + } + if (!talloc_reference(*user_info_mapped, user_info)) { + return NT_STATUS_NO_MEMORY; + } + **user_info_mapped = *user_info; + (*user_info_mapped)->mapped_state = true; + (*user_info_mapped)->mapped.domain_name = talloc_strdup(*user_info_mapped, domain); + (*user_info_mapped)->mapped.account_name = talloc_strdup(*user_info_mapped, account_name); + talloc_free(account_name); + if (!(*user_info_mapped)->mapped.domain_name + || !(*user_info_mapped)->mapped.account_name) { + return NT_STATUS_NO_MEMORY; + } + + return NT_STATUS_OK; +} + +/**************************************************************************** + Create an auth_usersupplied_data structure after appropriate mapping. +****************************************************************************/ + +NTSTATUS encrypt_user_info(TALLOC_CTX *mem_ctx, struct auth_context *auth_context, + enum auth_password_state to_state, + const struct auth_usersupplied_info *user_info_in, + const struct auth_usersupplied_info **user_info_encrypted) +{ + NTSTATUS nt_status; + struct auth_usersupplied_info *user_info_temp; + switch (to_state) { + case AUTH_PASSWORD_RESPONSE: + switch (user_info_in->password_state) { + case AUTH_PASSWORD_PLAIN: + { + const struct auth_usersupplied_info *user_info_temp2; + nt_status = encrypt_user_info(mem_ctx, auth_context, + AUTH_PASSWORD_HASH, + user_info_in, &user_info_temp2); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + user_info_in = user_info_temp2; + /* fall through */ + } + case AUTH_PASSWORD_HASH: + { + const uint8_t *challenge; + DATA_BLOB chall_blob; + user_info_temp = talloc(mem_ctx, struct auth_usersupplied_info); + if (!user_info_temp) { + return NT_STATUS_NO_MEMORY; + } + if (!talloc_reference(user_info_temp, user_info_in)) { + return NT_STATUS_NO_MEMORY; + } + *user_info_temp = *user_info_in; + user_info_temp->mapped_state = to_state; + + nt_status = auth_get_challenge(auth_context, &challenge); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + + chall_blob = data_blob_talloc(mem_ctx, challenge, 8); + if (lp_client_ntlmv2_auth(auth_context->lp_ctx)) { + DATA_BLOB names_blob = NTLMv2_generate_names_blob(mem_ctx, lp_iconv_convenience(auth_context->lp_ctx), lp_netbios_name(auth_context->lp_ctx), lp_workgroup(auth_context->lp_ctx)); + DATA_BLOB lmv2_response, ntlmv2_response, lmv2_session_key, ntlmv2_session_key; + + if (!SMBNTLMv2encrypt_hash(user_info_temp, + user_info_in->client.account_name, + user_info_in->client.domain_name, + user_info_in->password.hash.nt->hash, &chall_blob, + &names_blob, + &lmv2_response, &ntlmv2_response, + &lmv2_session_key, &ntlmv2_session_key)) { + data_blob_free(&names_blob); + return NT_STATUS_NO_MEMORY; + } + data_blob_free(&names_blob); + user_info_temp->password.response.lanman = lmv2_response; + user_info_temp->password.response.nt = ntlmv2_response; + + data_blob_free(&lmv2_session_key); + data_blob_free(&ntlmv2_session_key); + } else { + DATA_BLOB blob = data_blob_talloc(mem_ctx, NULL, 24); + SMBOWFencrypt(user_info_in->password.hash.nt->hash, challenge, blob.data); + + user_info_temp->password.response.nt = blob; + if (lp_client_lanman_auth(auth_context->lp_ctx) && user_info_in->password.hash.lanman) { + DATA_BLOB lm_blob = data_blob_talloc(mem_ctx, NULL, 24); + SMBOWFencrypt(user_info_in->password.hash.lanman->hash, challenge, blob.data); + user_info_temp->password.response.lanman = lm_blob; + } else { + /* if not sending the LM password, send the NT password twice */ + user_info_temp->password.response.lanman = user_info_temp->password.response.nt; + } + } + + user_info_in = user_info_temp; + /* fall through */ + } + case AUTH_PASSWORD_RESPONSE: + *user_info_encrypted = user_info_in; + } + break; + case AUTH_PASSWORD_HASH: + { + switch (user_info_in->password_state) { + case AUTH_PASSWORD_PLAIN: + { + struct samr_Password lanman; + struct samr_Password nt; + + user_info_temp = talloc(mem_ctx, struct auth_usersupplied_info); + if (!user_info_temp) { + return NT_STATUS_NO_MEMORY; + } + if (!talloc_reference(user_info_temp, user_info_in)) { + return NT_STATUS_NO_MEMORY; + } + *user_info_temp = *user_info_in; + user_info_temp->mapped_state = to_state; + + if (E_deshash(user_info_in->password.plaintext, lanman.hash)) { + user_info_temp->password.hash.lanman = talloc(user_info_temp, + struct samr_Password); + *user_info_temp->password.hash.lanman = lanman; + } else { + user_info_temp->password.hash.lanman = NULL; + } + + E_md4hash(user_info_in->password.plaintext, nt.hash); + user_info_temp->password.hash.nt = talloc(user_info_temp, + struct samr_Password); + *user_info_temp->password.hash.nt = nt; + + user_info_in = user_info_temp; + /* fall through */ + } + case AUTH_PASSWORD_HASH: + *user_info_encrypted = user_info_in; + break; + default: + return NT_STATUS_INVALID_PARAMETER; + break; + } + break; + } + default: + return NT_STATUS_INVALID_PARAMETER; + } + + return NT_STATUS_OK; +} + + +/** + * Squash an NT_STATUS in line with security requirements. + * In an attempt to avoid giving the whole game away when users + * are authenticating, NT replaces both NT_STATUS_NO_SUCH_USER and + * NT_STATUS_WRONG_PASSWORD with NT_STATUS_LOGON_FAILURE in certain situations + * (session setups in particular). + * + * @param nt_status NTSTATUS input for squashing. + * @return the 'squashed' nt_status + **/ +_PUBLIC_ NTSTATUS auth_nt_status_squash(NTSTATUS nt_status) +{ + if NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER) { + /* Match WinXP and don't give the game away */ + return NT_STATUS_LOGON_FAILURE; + } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) { + /* Match WinXP and don't give the game away */ + return NT_STATUS_LOGON_FAILURE; + } + + return nt_status; +} diff --git a/source4/auth/ntlm/auth_winbind.c b/source4/auth/ntlm/auth_winbind.c new file mode 100644 index 0000000000..149f549afa --- /dev/null +++ b/source4/auth/ntlm/auth_winbind.c @@ -0,0 +1,282 @@ +/* + Unix SMB/CIFS implementation. + + Winbind authentication mechnism + + Copyright (C) Tim Potter 2000 + Copyright (C) Andrew Bartlett 2001 - 2002 + Copyright (C) Stefan Metzmacher 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 3 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, see . +*/ + +#include "includes.h" +#include "auth/auth.h" +#include "auth/auth_proto.h" +#include "auth/session_proto.h" +#include "nsswitch/winbind_client.h" +#include "librpc/gen_ndr/ndr_netlogon.h" +#include "librpc/gen_ndr/ndr_winbind.h" +#include "lib/messaging/irpc.h" +#include "param/param.h" + +static NTSTATUS get_info3_from_ndr(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience, struct winbindd_response *response, struct netr_SamInfo3 *info3) +{ + size_t len = response->length - sizeof(struct winbindd_response); + if (len > 4) { + enum ndr_err_code ndr_err; + DATA_BLOB blob; + blob.length = len - 4; + blob.data = (uint8_t *)(((char *)response->extra_data.data) + 4); + + ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, + iconv_convenience, info3, + (ndr_pull_flags_fn_t)ndr_pull_netr_SamInfo3); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return ndr_map_error2ntstatus(ndr_err); + } + + return NT_STATUS_OK; + } else { + DEBUG(2, ("get_info3_from_ndr: No info3 struct found!\n")); + return NT_STATUS_UNSUCCESSFUL; + } +} + +static NTSTATUS winbind_want_check(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info) +{ + if (!user_info->mapped.account_name || !*user_info->mapped.account_name) { + return NT_STATUS_NOT_IMPLEMENTED; + } + + /* TODO: maybe limit the user scope to remote users only */ + return NT_STATUS_OK; +} + +/* + Authenticate a user with a challenge/response + using the samba3 winbind protocol +*/ +static NTSTATUS winbind_check_password_samba3(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info, + struct auth_serversupplied_info **server_info) +{ + struct winbindd_request request; + struct winbindd_response response; + NSS_STATUS result; + NTSTATUS nt_status; + struct netr_SamInfo3 info3; + + /* Send off request */ + const struct auth_usersupplied_info *user_info_temp; + nt_status = encrypt_user_info(mem_ctx, ctx->auth_ctx, + AUTH_PASSWORD_RESPONSE, + user_info, &user_info_temp); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + user_info = user_info_temp; + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + request.flags = WBFLAG_PAM_INFO3_NDR; + + request.data.auth_crap.logon_parameters = user_info->logon_parameters; + + safe_strcpy(request.data.auth_crap.user, + user_info->client.account_name, sizeof(fstring)); + safe_strcpy(request.data.auth_crap.domain, + user_info->client.domain_name, sizeof(fstring)); + safe_strcpy(request.data.auth_crap.workstation, + user_info->workstation_name, sizeof(fstring)); + + memcpy(request.data.auth_crap.chal, ctx->auth_ctx->challenge.data.data, sizeof(request.data.auth_crap.chal)); + + request.data.auth_crap.lm_resp_len = MIN(user_info->password.response.lanman.length, + sizeof(request.data.auth_crap.lm_resp)); + request.data.auth_crap.nt_resp_len = MIN(user_info->password.response.nt.length, + sizeof(request.data.auth_crap.nt_resp)); + + memcpy(request.data.auth_crap.lm_resp, user_info->password.response.lanman.data, + request.data.auth_crap.lm_resp_len); + memcpy(request.data.auth_crap.nt_resp, user_info->password.response.nt.data, + request.data.auth_crap.nt_resp_len); + + result = winbindd_request_response(WINBINDD_PAM_AUTH_CRAP, &request, &response); + + nt_status = NT_STATUS(response.data.auth.nt_status); + NT_STATUS_NOT_OK_RETURN(nt_status); + + if (result == NSS_STATUS_SUCCESS && response.extra_data.data) { + union netr_Validation validation; + + nt_status = get_info3_from_ndr(mem_ctx, lp_iconv_convenience(ctx->auth_ctx->lp_ctx), &response, &info3); + SAFE_FREE(response.extra_data.data); + NT_STATUS_NOT_OK_RETURN(nt_status); + + validation.sam3 = &info3; + nt_status = make_server_info_netlogon_validation(mem_ctx, + user_info->client.account_name, + 3, &validation, + server_info); + return nt_status; + } else if (result == NSS_STATUS_SUCCESS && !response.extra_data.data) { + DEBUG(0, ("Winbindd authenticated the user [%s]\\[%s], " + "but did not include the required info3 reply!\n", + user_info->client.domain_name, user_info->client.account_name)); + return NT_STATUS_INSUFFICIENT_LOGON_INFO; + } else if (NT_STATUS_IS_OK(nt_status)) { + DEBUG(1, ("Winbindd authentication for [%s]\\[%s] failed, " + "but no error code is available!\n", + user_info->client.domain_name, user_info->client.account_name)); + return NT_STATUS_NO_LOGON_SERVERS; + } + + return nt_status; +} + +struct winbind_check_password_state { + struct winbind_SamLogon req; +}; + +/* + Authenticate a user with a challenge/response + using IRPC to the winbind task +*/ +static NTSTATUS winbind_check_password(struct auth_method_context *ctx, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info, + struct auth_serversupplied_info **server_info) +{ + NTSTATUS status; + struct server_id *winbind_servers; + struct winbind_check_password_state *s; + const struct auth_usersupplied_info *user_info_new; + struct netr_IdentityInfo *identity_info; + + s = talloc(mem_ctx, struct winbind_check_password_state); + NT_STATUS_HAVE_NO_MEMORY(s); + + winbind_servers = irpc_servers_byname(ctx->auth_ctx->msg_ctx, s, "winbind_server"); + if ((winbind_servers == NULL) || (winbind_servers[0].id == 0)) { + DEBUG(0, ("Winbind authentication for [%s]\\[%s] failed, " + "no winbind_server running!\n", + user_info->client.domain_name, user_info->client.account_name)); + return NT_STATUS_NO_LOGON_SERVERS; + } + + if (user_info->flags & USER_INFO_INTERACTIVE_LOGON) { + struct netr_PasswordInfo *password_info; + + status = encrypt_user_info(s, ctx->auth_ctx, AUTH_PASSWORD_HASH, + user_info, &user_info_new); + NT_STATUS_NOT_OK_RETURN(status); + user_info = user_info_new; + + password_info = talloc(s, struct netr_PasswordInfo); + NT_STATUS_HAVE_NO_MEMORY(password_info); + + password_info->lmpassword = *user_info->password.hash.lanman; + password_info->ntpassword = *user_info->password.hash.nt; + + identity_info = &password_info->identity_info; + s->req.in.logon_level = 1; + s->req.in.logon.password= password_info; + } else { + struct netr_NetworkInfo *network_info; + const uint8_t *challenge; + + status = encrypt_user_info(s, ctx->auth_ctx, AUTH_PASSWORD_RESPONSE, + user_info, &user_info_new); + NT_STATUS_NOT_OK_RETURN(status); + user_info = user_info_new; + + network_info = talloc(s, struct netr_NetworkInfo); + NT_STATUS_HAVE_NO_MEMORY(network_info); + + status = auth_get_challenge(ctx->auth_ctx, &challenge); + NT_STATUS_NOT_OK_RETURN(status); + + memcpy(network_info->challenge, challenge, sizeof(network_info->challenge)); + + network_info->nt.length = user_info->password.response.nt.length; + network_info->nt.data = user_info->password.response.nt.data; + + network_info->lm.length = user_info->password.response.lanman.length; + network_info->lm.data = user_info->password.response.lanman.data; + + identity_info = &network_info->identity_info; + s->req.in.logon_level = 2; + s->req.in.logon.network = network_info; + } + + identity_info->domain_name.string = user_info->client.domain_name; + identity_info->parameter_control = user_info->logon_parameters; /* see MSV1_0_* */ + identity_info->logon_id_low = 0; + identity_info->logon_id_high = 0; + identity_info->account_name.string = user_info->client.account_name; + identity_info->workstation.string = user_info->workstation_name; + + s->req.in.validation_level = 3; + + status = IRPC_CALL(ctx->auth_ctx->msg_ctx, winbind_servers[0], + winbind, WINBIND_SAMLOGON, + &s->req, s); + NT_STATUS_NOT_OK_RETURN(status); + + status = make_server_info_netlogon_validation(mem_ctx, + user_info->client.account_name, + s->req.in.validation_level, + &s->req.out.validation, + server_info); + NT_STATUS_NOT_OK_RETURN(status); + + return NT_STATUS_OK; +} + +static const struct auth_operations winbind_samba3_ops = { + .name = "winbind_samba3", + .get_challenge = auth_get_challenge_not_implemented, + .want_check = winbind_want_check, + .check_password = winbind_check_password_samba3 +}; + +static const struct auth_operations winbind_ops = { + .name = "winbind", + .get_challenge = auth_get_challenge_not_implemented, + .want_check = winbind_want_check, + .check_password = winbind_check_password +}; + +_PUBLIC_ NTSTATUS auth_winbind_init(void) +{ + NTSTATUS ret; + + ret = auth_register(&winbind_samba3_ops); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(0,("Failed to register 'winbind_samba3' auth backend!\n")); + return ret; + } + + ret = auth_register(&winbind_ops); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(0,("Failed to register 'winbind' auth backend!\n")); + return ret; + } + + return NT_STATUS_OK; +} diff --git a/source4/auth/ntlm/config.mk b/source4/auth/ntlm/config.mk new file mode 100644 index 0000000000..319aca7318 --- /dev/null +++ b/source4/auth/ntlm/config.mk @@ -0,0 +1,87 @@ +# NTLM auth server subsystem + +[SUBSYSTEM::ntlm_check] +PRIVATE_DEPENDENCIES = LIBSAMBA-UTIL + +ntlm_check_OBJ_FILES = $(addprefix auth/ntlm/, ntlm_check.o) + +####################### +# Start MODULE auth_sam +[MODULE::auth_sam_module] +# gensec_krb5 and gensec_gssapi depend on it +INIT_FUNCTION = auth_sam_init +SUBSYSTEM = auth +PRIVATE_DEPENDENCIES = \ + SAMDB auth_sam ntlm_check +# End MODULE auth_sam +####################### + +auth_sam_module_OBJ_FILES = $(addprefix auth/ntlm/, auth_sam.o) + +####################### +# Start MODULE auth_anonymous +[MODULE::auth_anonymous] +INIT_FUNCTION = auth_anonymous_init +SUBSYSTEM = auth +# End MODULE auth_anonymous +####################### + +auth_anonymous_OBJ_FILES = $(addprefix auth/ntlm/, auth_anonymous.o) + +####################### +# Start MODULE auth_anonymous +[MODULE::auth_server] +INIT_FUNCTION = auth_server_init +SUBSYSTEM = auth +PRIVATE_DEPENDENCIES = LIBSAMBA-UTIL LIBCLI_SMB +OUTPUT_TYPE = SHARED_LIBRARY +# End MODULE auth_server +####################### + +auth_server_OBJ_FILES = $(addprefix auth/ntlm/, auth_server.o) + +####################### +# Start MODULE auth_winbind +[MODULE::auth_winbind] +INIT_FUNCTION = auth_winbind_init +SUBSYSTEM = auth +PRIVATE_DEPENDENCIES = NDR_WINBIND MESSAGING LIBWINBIND-CLIENT +# End MODULE auth_winbind +####################### + +auth_winbind_OBJ_FILES = $(addprefix auth/ntlm/, auth_winbind.o) + +####################### +# Start MODULE auth_developer +[MODULE::auth_developer] +INIT_FUNCTION = auth_developer_init +SUBSYSTEM = auth +# End MODULE auth_developer +####################### + +auth_developer_OBJ_FILES = $(addprefix auth/ntlm/, auth_developer.o) + +[MODULE::auth_unix] +INIT_FUNCTION = auth_unix_init +SUBSYSTEM = auth +PRIVATE_DEPENDENCIES = CRYPT PAM PAM_ERRORS NSS_WRAPPER + +auth_unix_OBJ_FILES = $(addprefix auth/ntlm/, auth_unix.o) + +[SUBSYSTEM::PAM_ERRORS] +PRIVATE_PROTO_HEADER = pam_errors.h + +#VERSION = 0.0.1 +#SO_VERSION = 0 +PAM_ERRORS_OBJ_FILES = $(addprefix auth/ntlm/, pam_errors.o) + +[MODULE::auth] +INIT_FUNCTION = server_service_auth_init +SUBSYSTEM = service +PRIVATE_PROTO_HEADER = auth_proto.h +PRIVATE_DEPENDENCIES = LIBSAMBA-UTIL LIBSECURITY SAMDB CREDENTIALS + +auth_OBJ_FILES = $(addprefix auth/ntlm/, auth.o auth_util.o auth_simple.o) + +# PUBLIC_HEADERS += auth/auth.h + diff --git a/source4/auth/ntlm/ntlm_check.c b/source4/auth/ntlm/ntlm_check.c new file mode 100644 index 0000000000..0dbbce0edc --- /dev/null +++ b/source4/auth/ntlm/ntlm_check.c @@ -0,0 +1,603 @@ +/* + Unix SMB/CIFS implementation. + Password and authentication handling + Copyright (C) Andrew Bartlett 2001-2004 + Copyright (C) Gerald Carter 2003 + Copyright (C) Luke Kenneth Casson Leighton 1996-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 3 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, see . +*/ + +#include "includes.h" +#include "lib/crypto/crypto.h" +#include "librpc/gen_ndr/netlogon.h" +#include "libcli/auth/libcli_auth.h" +#include "param/param.h" +#include "auth/ntlm/ntlm_check.h" + +/**************************************************************************** + Core of smb password checking routine. +****************************************************************************/ + +static bool smb_pwd_check_ntlmv1(TALLOC_CTX *mem_ctx, + const DATA_BLOB *nt_response, + const uint8_t *part_passwd, + const DATA_BLOB *sec_blob, + DATA_BLOB *user_sess_key) +{ + /* Finish the encryption of part_passwd. */ + uint8_t p24[24]; + + if (part_passwd == NULL) { + DEBUG(10,("No password set - DISALLOWING access\n")); + /* No password set - always false ! */ + return false; + } + + if (sec_blob->length != 8) { + DEBUG(0, ("smb_pwd_check_ntlmv1: incorrect challenge size (%lu)\n", + (unsigned long)sec_blob->length)); + return false; + } + + if (nt_response->length != 24) { + DEBUG(0, ("smb_pwd_check_ntlmv1: incorrect password length (%lu)\n", + (unsigned long)nt_response->length)); + return false; + } + + SMBOWFencrypt(part_passwd, sec_blob->data, p24); + +#if DEBUG_PASSWORD + DEBUG(100,("Part password (P16) was |\n")); + dump_data(100, part_passwd, 16); + DEBUGADD(100,("Password from client was |\n")); + dump_data(100, nt_response->data, nt_response->length); + DEBUGADD(100,("Given challenge was |\n")); + dump_data(100, sec_blob->data, sec_blob->length); + DEBUGADD(100,("Value from encryption was |\n")); + dump_data(100, p24, 24); +#endif + if (memcmp(p24, nt_response->data, 24) == 0) { + if (user_sess_key != NULL) { + *user_sess_key = data_blob_talloc(mem_ctx, NULL, 16); + SMBsesskeygen_ntv1(part_passwd, user_sess_key->data); + } + return true; + } + return false; +} + +/**************************************************************************** + Core of smb password checking routine. (NTLMv2, LMv2) + Note: The same code works with both NTLMv2 and LMv2. +****************************************************************************/ + +static bool smb_pwd_check_ntlmv2(TALLOC_CTX *mem_ctx, + const DATA_BLOB *ntv2_response, + const uint8_t *part_passwd, + const DATA_BLOB *sec_blob, + const char *user, const char *domain, + bool upper_case_domain, /* should the domain be transformed into upper case? */ + DATA_BLOB *user_sess_key) +{ + /* Finish the encryption of part_passwd. */ + uint8_t kr[16]; + uint8_t value_from_encryption[16]; + DATA_BLOB client_key_data; + + if (part_passwd == NULL) { + DEBUG(10,("No password set - DISALLOWING access\n")); + /* No password set - always false */ + return false; + } + + if (sec_blob->length != 8) { + DEBUG(0, ("smb_pwd_check_ntlmv2: incorrect challenge size (%lu)\n", + (unsigned long)sec_blob->length)); + return false; + } + + if (ntv2_response->length < 24) { + /* We MUST have more than 16 bytes, or the stuff below will go + crazy. No known implementation sends less than the 24 bytes + for LMv2, let alone NTLMv2. */ + DEBUG(0, ("smb_pwd_check_ntlmv2: incorrect password length (%lu)\n", + (unsigned long)ntv2_response->length)); + return false; + } + + client_key_data = data_blob_talloc(mem_ctx, ntv2_response->data+16, ntv2_response->length-16); + /* + todo: should we be checking this for anything? We can't for LMv2, + but for NTLMv2 it is meant to contain the current time etc. + */ + + if (!ntv2_owf_gen(part_passwd, user, domain, upper_case_domain, kr)) { + return false; + } + + SMBOWFencrypt_ntv2(kr, sec_blob, &client_key_data, value_from_encryption); + +#if DEBUG_PASSWORD + DEBUG(100,("Part password (P16) was |\n")); + dump_data(100, part_passwd, 16); + DEBUGADD(100,("Password from client was |\n")); + dump_data(100, ntv2_response->data, ntv2_response->length); + DEBUGADD(100,("Variable data from client was |\n")); + dump_data(100, client_key_data.data, client_key_data.length); + DEBUGADD(100,("Given challenge was |\n")); + dump_data(100, sec_blob->data, sec_blob->length); + DEBUGADD(100,("Value from encryption was |\n")); + dump_data(100, value_from_encryption, 16); +#endif + data_blob_clear_free(&client_key_data); + if (memcmp(value_from_encryption, ntv2_response->data, 16) == 0) { + if (user_sess_key != NULL) { + *user_sess_key = data_blob_talloc(mem_ctx, NULL, 16); + SMBsesskeygen_ntv2(kr, value_from_encryption, user_sess_key->data); + } + return true; + } + return false; +} + +/**************************************************************************** + Core of smb password checking routine. (NTLMv2, LMv2) + Note: The same code works with both NTLMv2 and LMv2. +****************************************************************************/ + +static bool smb_sess_key_ntlmv2(TALLOC_CTX *mem_ctx, + const DATA_BLOB *ntv2_response, + const uint8_t *part_passwd, + const DATA_BLOB *sec_blob, + const char *user, const char *domain, + bool upper_case_domain, /* should the domain be transformed into upper case? */ + DATA_BLOB *user_sess_key) +{ + /* Finish the encryption of part_passwd. */ + uint8_t kr[16]; + uint8_t value_from_encryption[16]; + DATA_BLOB client_key_data; + + if (part_passwd == NULL) { + DEBUG(10,("No password set - DISALLOWING access\n")); + /* No password set - always false */ + return false; + } + + if (sec_blob->length != 8) { + DEBUG(0, ("smb_sess_key_ntlmv2: incorrect challenge size (%lu)\n", + (unsigned long)sec_blob->length)); + return false; + } + + if (ntv2_response->length < 24) { + /* We MUST have more than 16 bytes, or the stuff below will go + crazy. No known implementation sends less than the 24 bytes + for LMv2, let alone NTLMv2. */ + DEBUG(0, ("smb_sess_key_ntlmv2: incorrect password length (%lu)\n", + (unsigned long)ntv2_response->length)); + return false; + } + + client_key_data = data_blob_talloc(mem_ctx, ntv2_response->data+16, ntv2_response->length-16); + + if (!ntv2_owf_gen(part_passwd, user, domain, upper_case_domain, kr)) { + return false; + } + + SMBOWFencrypt_ntv2(kr, sec_blob, &client_key_data, value_from_encryption); + *user_sess_key = data_blob_talloc(mem_ctx, NULL, 16); + SMBsesskeygen_ntv2(kr, value_from_encryption, user_sess_key->data); + return true; +} + +/** + * Compare password hashes against those from the SAM + * + * @param mem_ctx talloc context + * @param client_lanman LANMAN password hash, as supplied by the client + * @param client_nt NT (MD4) password hash, as supplied by the client + * @param username internal Samba username, for log messages + * @param client_username username the client used + * @param client_domain domain name the client used (may be mapped) + * @param stored_lanman LANMAN password hash, as stored on the SAM + * @param stored_nt NT (MD4) password hash, as stored on the SAM + * @param user_sess_key User session key + * @param lm_sess_key LM session key (first 8 bytes of the LM hash) + */ + +NTSTATUS hash_password_check(TALLOC_CTX *mem_ctx, + struct loadparm_context *lp_ctx, + const struct samr_Password *client_lanman, + const struct samr_Password *client_nt, + const char *username, + const struct samr_Password *stored_lanman, + const struct samr_Password *stored_nt) +{ + if (stored_nt == NULL) { + DEBUG(3,("ntlm_password_check: NO NT password stored for user %s.\n", + username)); + } + + if (client_nt && stored_nt) { + if (memcmp(client_nt->hash, stored_nt->hash, sizeof(stored_nt->hash)) == 0) { + return NT_STATUS_OK; + } else { + DEBUG(3,("ntlm_password_check: Interactive logon: NT password check failed for user %s\n", + username)); + return NT_STATUS_WRONG_PASSWORD; + } + + } else if (client_lanman && stored_lanman) { + if (!lp_lanman_auth(lp_ctx)) { + DEBUG(3,("ntlm_password_check: Interactive logon: only LANMAN password supplied for user %s, and LM passwords are disabled!\n", + username)); + return NT_STATUS_WRONG_PASSWORD; + } + if (strchr_m(username, '@')) { + return NT_STATUS_NOT_FOUND; + } + + if (memcmp(client_lanman->hash, stored_lanman->hash, sizeof(stored_lanman->hash)) == 0) { + return NT_STATUS_OK; + } else { + DEBUG(3,("ntlm_password_check: Interactive logon: LANMAN password check failed for user %s\n", + username)); + return NT_STATUS_WRONG_PASSWORD; + } + } + if (strchr_m(username, '@')) { + return NT_STATUS_NOT_FOUND; + } + return NT_STATUS_WRONG_PASSWORD; +} + +/** + * Check a challenge-response password against the value of the NT or + * LM password hash. + * + * @param mem_ctx talloc context + * @param challenge 8-byte challenge. If all zero, forces plaintext comparison + * @param nt_response 'unicode' NT response to the challenge, or unicode password + * @param lm_response ASCII or LANMAN response to the challenge, or password in DOS code page + * @param username internal Samba username, for log messages + * @param client_username username the client used + * @param client_domain domain name the client used (may be mapped) + * @param stored_lanman LANMAN ASCII password from our passdb or similar + * @param stored_nt MD4 unicode password from our passdb or similar + * @param user_sess_key User session key + * @param lm_sess_key LM session key (first 8 bytes of the LM hash) + */ + +NTSTATUS ntlm_password_check(TALLOC_CTX *mem_ctx, + struct loadparm_context *lp_ctx, + uint32_t logon_parameters, + const DATA_BLOB *challenge, + const DATA_BLOB *lm_response, + const DATA_BLOB *nt_response, + const char *username, + const char *client_username, + const char *client_domain, + const struct samr_Password *stored_lanman, + const struct samr_Password *stored_nt, + DATA_BLOB *user_sess_key, + DATA_BLOB *lm_sess_key) +{ + const static uint8_t zeros[8]; + DATA_BLOB tmp_sess_key; + + if (stored_nt == NULL) { + DEBUG(3,("ntlm_password_check: NO NT password stored for user %s.\n", + username)); + } + + *lm_sess_key = data_blob(NULL, 0); + *user_sess_key = data_blob(NULL, 0); + + /* Check for cleartext netlogon. Used by Exchange 5.5. */ + if ((logon_parameters & MSV1_0_CLEARTEXT_PASSWORD_ALLOWED) + && challenge->length == sizeof(zeros) + && (memcmp(challenge->data, zeros, challenge->length) == 0 )) { + struct samr_Password client_nt; + struct samr_Password client_lm; + char *unix_pw = NULL; + bool lm_ok; + + DEBUG(4,("ntlm_password_check: checking plaintext passwords for user %s\n", + username)); + mdfour(client_nt.hash, nt_response->data, nt_response->length); + + if (lm_response->length && + (convert_string_talloc(mem_ctx, lp_iconv_convenience(lp_ctx), CH_DOS, CH_UNIX, + lm_response->data, lm_response->length, + (void **)&unix_pw) != -1)) { + if (E_deshash(unix_pw, client_lm.hash)) { + lm_ok = true; + } else { + lm_ok = false; + } + } else { + lm_ok = false; + } + return hash_password_check(mem_ctx, + lp_ctx, + lm_ok ? &client_lm : NULL, + nt_response->length ? &client_nt : NULL, + username, + stored_lanman, stored_nt); + } + + if (nt_response->length != 0 && nt_response->length < 24) { + DEBUG(2,("ntlm_password_check: invalid NT password length (%lu) for user %s\n", + (unsigned long)nt_response->length, username)); + } + + if (nt_response->length > 24 && stored_nt) { + /* We have the NT MD4 hash challenge available - see if we can + use it + */ + DEBUG(4,("ntlm_password_check: Checking NTLMv2 password with domain [%s]\n", client_domain)); + if (smb_pwd_check_ntlmv2(mem_ctx, + nt_response, + stored_nt->hash, challenge, + client_username, + client_domain, + false, + user_sess_key)) { + *lm_sess_key = *user_sess_key; + if (user_sess_key->length) { + lm_sess_key->length = 8; + } + return NT_STATUS_OK; + } + + DEBUG(4,("ntlm_password_check: Checking NTLMv2 password with uppercased version of domain [%s]\n", client_domain)); + if (smb_pwd_check_ntlmv2(mem_ctx, + nt_response, + stored_nt->hash, challenge, + client_username, + client_domain, + true, + user_sess_key)) { + *lm_sess_key = *user_sess_key; + if (user_sess_key->length) { + lm_sess_key->length = 8; + } + return NT_STATUS_OK; + } + + DEBUG(4,("ntlm_password_check: Checking NTLMv2 password without a domain\n")); + if (smb_pwd_check_ntlmv2(mem_ctx, + nt_response, + stored_nt->hash, challenge, + client_username, + "", + false, + user_sess_key)) { + *lm_sess_key = *user_sess_key; + if (user_sess_key->length) { + lm_sess_key->length = 8; + } + return NT_STATUS_OK; + } else { + DEBUG(3,("ntlm_password_check: NTLMv2 password check failed\n")); + } + } else if (nt_response->length == 24 && stored_nt) { + if (lp_ntlm_auth(lp_ctx)) { + /* We have the NT MD4 hash challenge available - see if we can + use it (ie. does it exist in the smbpasswd file). + */ + DEBUG(4,("ntlm_password_check: Checking NT MD4 password\n")); + if (smb_pwd_check_ntlmv1(mem_ctx, + nt_response, + stored_nt->hash, challenge, + user_sess_key)) { + /* The LM session key for this response is not very secure, + so use it only if we otherwise allow LM authentication */ + + if (lp_lanman_auth(lp_ctx) && stored_lanman) { + *lm_sess_key = data_blob_talloc(mem_ctx, stored_lanman->hash, 8); + } + return NT_STATUS_OK; + } else { + DEBUG(3,("ntlm_password_check: NT MD4 password check failed for user %s\n", + username)); + return NT_STATUS_WRONG_PASSWORD; + } + } else { + DEBUG(2,("ntlm_password_check: NTLMv1 passwords NOT PERMITTED for user %s\n", + username)); + /* no return, becouse we might pick up LMv2 in the LM field */ + } + } + + if (lm_response->length == 0) { + DEBUG(3,("ntlm_password_check: NEITHER LanMan nor NT password supplied for user %s\n", + username)); + return NT_STATUS_WRONG_PASSWORD; + } + + if (lm_response->length < 24) { + DEBUG(2,("ntlm_password_check: invalid LanMan password length (%lu) for user %s\n", + (unsigned long)nt_response->length, username)); + return NT_STATUS_WRONG_PASSWORD; + } + + if (!lp_lanman_auth(lp_ctx)) { + DEBUG(3,("ntlm_password_check: Lanman passwords NOT PERMITTED for user %s\n", + username)); + } else if (!stored_lanman) { + DEBUG(3,("ntlm_password_check: NO LanMan password set for user %s (and no NT password supplied)\n", + username)); + } else if (strchr_m(username, '@')) { + DEBUG(3,("ntlm_password_check: NO LanMan password allowed for username@realm logins (user: %s)\n", + username)); + } else { + DEBUG(4,("ntlm_password_check: Checking LM password\n")); + if (smb_pwd_check_ntlmv1(mem_ctx, + lm_response, + stored_lanman->hash, challenge, + NULL)) { + /* The session key for this response is still very odd. + It not very secure, so use it only if we otherwise + allow LM authentication */ + + if (lp_lanman_auth(lp_ctx) && stored_lanman) { + uint8_t first_8_lm_hash[16]; + memcpy(first_8_lm_hash, stored_lanman->hash, 8); + memset(first_8_lm_hash + 8, '\0', 8); + *user_sess_key = data_blob_talloc(mem_ctx, first_8_lm_hash, 16); + *lm_sess_key = data_blob_talloc(mem_ctx, stored_lanman->hash, 8); + } + return NT_STATUS_OK; + } + } + + if (!stored_nt) { + DEBUG(4,("ntlm_password_check: LM password check failed for user, no NT password %s\n",username)); + return NT_STATUS_WRONG_PASSWORD; + } + + /* This is for 'LMv2' authentication. almost NTLMv2 but limited to 24 bytes. + - related to Win9X, legacy NAS pass-though authentication + */ + DEBUG(4,("ntlm_password_check: Checking LMv2 password with domain %s\n", client_domain)); + if (smb_pwd_check_ntlmv2(mem_ctx, + lm_response, + stored_nt->hash, challenge, + client_username, + client_domain, + false, + &tmp_sess_key)) { + if (nt_response->length > 24) { + /* If NTLMv2 authentication has preceeded us + * (even if it failed), then use the session + * key from that. See the RPC-SAMLOGON + * torture test */ + smb_sess_key_ntlmv2(mem_ctx, + nt_response, + stored_nt->hash, challenge, + client_username, + client_domain, + false, + user_sess_key); + } else { + /* Otherwise, use the LMv2 session key */ + *user_sess_key = tmp_sess_key; + } + *lm_sess_key = *user_sess_key; + if (user_sess_key->length) { + lm_sess_key->length = 8; + } + return NT_STATUS_OK; + } + + DEBUG(4,("ntlm_password_check: Checking LMv2 password with upper-cased version of domain %s\n", client_domain)); + if (smb_pwd_check_ntlmv2(mem_ctx, + lm_response, + stored_nt->hash, challenge, + client_username, + client_domain, + true, + &tmp_sess_key)) { + if (nt_response->length > 24) { + /* If NTLMv2 authentication has preceeded us + * (even if it failed), then use the session + * key from that. See the RPC-SAMLOGON + * torture test */ + smb_sess_key_ntlmv2(mem_ctx, + nt_response, + stored_nt->hash, challenge, + client_username, + client_domain, + true, + user_sess_key); + } else { + /* Otherwise, use the LMv2 session key */ + *user_sess_key = tmp_sess_key; + } + *lm_sess_key = *user_sess_key; + if (user_sess_key->length) { + lm_sess_key->length = 8; + } + return NT_STATUS_OK; + } + + DEBUG(4,("ntlm_password_check: Checking LMv2 password without a domain\n")); + if (smb_pwd_check_ntlmv2(mem_ctx, + lm_response, + stored_nt->hash, challenge, + client_username, + "", + false, + &tmp_sess_key)) { + if (nt_response->length > 24) { + /* If NTLMv2 authentication has preceeded us + * (even if it failed), then use the session + * key from that. See the RPC-SAMLOGON + * torture test */ + smb_sess_key_ntlmv2(mem_ctx, + nt_response, + stored_nt->hash, challenge, + client_username, + "", + false, + user_sess_key); + } else { + /* Otherwise, use the LMv2 session key */ + *user_sess_key = tmp_sess_key; + } + *lm_sess_key = *user_sess_key; + if (user_sess_key->length) { + lm_sess_key->length = 8; + } + return NT_STATUS_OK; + } + + /* Apparently NT accepts NT responses in the LM field + - I think this is related to Win9X pass-though authentication + */ + DEBUG(4,("ntlm_password_check: Checking NT MD4 password in LM field\n")); + if (lp_ntlm_auth(lp_ctx)) { + if (smb_pwd_check_ntlmv1(mem_ctx, + lm_response, + stored_nt->hash, challenge, + NULL)) { + /* The session key for this response is still very odd. + It not very secure, so use it only if we otherwise + allow LM authentication */ + + if (lp_lanman_auth(lp_ctx) && stored_lanman) { + uint8_t first_8_lm_hash[16]; + memcpy(first_8_lm_hash, stored_lanman->hash, 8); + memset(first_8_lm_hash + 8, '\0', 8); + *user_sess_key = data_blob_talloc(mem_ctx, first_8_lm_hash, 16); + *lm_sess_key = data_blob_talloc(mem_ctx, stored_lanman->hash, 8); + } + return NT_STATUS_OK; + } + DEBUG(3,("ntlm_password_check: LM password, NT MD4 password in LM field and LMv2 failed for user %s\n",username)); + } else { + DEBUG(3,("ntlm_password_check: LM password and LMv2 failed for user %s, and NT MD4 password in LM field not permitted\n",username)); + } + + /* Try and match error codes */ + if (strchr_m(username, '@')) { + return NT_STATUS_NOT_FOUND; + } + return NT_STATUS_WRONG_PASSWORD; +} + diff --git a/source4/auth/ntlm/ntlm_check.h b/source4/auth/ntlm/ntlm_check.h new file mode 100644 index 0000000000..eb115b74d6 --- /dev/null +++ b/source4/auth/ntlm/ntlm_check.h @@ -0,0 +1,75 @@ +/* + Unix SMB/CIFS implementation. + Password and authentication handling + Copyright (C) Andrew Bartlett 2001-2004 + Copyright (C) Gerald Carter 2003 + Copyright (C) Luke Kenneth Casson Leighton 1996-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 3 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, see . +*/ + + +/** + * Compare password hashes against those from the SAM + * + * @param mem_ctx talloc context + * @param client_lanman LANMAN password hash, as supplied by the client + * @param client_nt NT (MD4) password hash, as supplied by the client + * @param username internal Samba username, for log messages + * @param client_username username the client used + * @param client_domain domain name the client used (may be mapped) + * @param stored_lanman LANMAN password hash, as stored on the SAM + * @param stored_nt NT (MD4) password hash, as stored on the SAM + * @param user_sess_key User session key + * @param lm_sess_key LM session key (first 8 bytes of the LM hash) + */ + +NTSTATUS hash_password_check(TALLOC_CTX *mem_ctx, + struct loadparm_context *lp_ctx, + const struct samr_Password *client_lanman, + const struct samr_Password *client_nt, + const char *username, + const struct samr_Password *stored_lanman, + const struct samr_Password *stored_nt); + +/** + * Check a challenge-response password against the value of the NT or + * LM password hash. + * + * @param mem_ctx talloc context + * @param challenge 8-byte challenge. If all zero, forces plaintext comparison + * @param nt_response 'unicode' NT response to the challenge, or unicode password + * @param lm_response ASCII or LANMAN response to the challenge, or password in DOS code page + * @param username internal Samba username, for log messages + * @param client_username username the client used + * @param client_domain domain name the client used (may be mapped) + * @param stored_lanman LANMAN ASCII password from our passdb or similar + * @param stored_nt MD4 unicode password from our passdb or similar + * @param user_sess_key User session key + * @param lm_sess_key LM session key (first 8 bytes of the LM hash) + */ + +NTSTATUS ntlm_password_check(TALLOC_CTX *mem_ctx, + struct loadparm_context *lp_ctx, + uint32_t logon_parameters, + const DATA_BLOB *challenge, + const DATA_BLOB *lm_response, + const DATA_BLOB *nt_response, + const char *username, + const char *client_username, + const char *client_domain, + const struct samr_Password *stored_lanman, + const struct samr_Password *stored_nt, + DATA_BLOB *user_sess_key, + DATA_BLOB *lm_sess_key); diff --git a/source4/auth/ntlm/pam_errors.c b/source4/auth/ntlm/pam_errors.c new file mode 100644 index 0000000000..9774ad8727 --- /dev/null +++ b/source4/auth/ntlm/pam_errors.c @@ -0,0 +1,125 @@ +/* + * Unix SMB/CIFS implementation. + * PAM error mapping functions + * 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 3 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, see . + */ + +#include "includes.h" + +#ifdef WITH_HAVE_SECURITY_PAM_APPL_H +#include + +#if defined(PAM_AUTHTOK_RECOVERY_ERR) && !defined(PAM_AUTHTOK_RECOVER_ERR) +#define PAM_AUTHTOK_RECOVER_ERR PAM_AUTHTOK_RECOVERY_ERR +#endif + +/* PAM -> NT_STATUS map */ +static const struct { + int pam_code; + NTSTATUS ntstatus; +} pam_to_nt_status_map[] = { + {PAM_OPEN_ERR, NT_STATUS_UNSUCCESSFUL}, + {PAM_SYMBOL_ERR, NT_STATUS_UNSUCCESSFUL}, + {PAM_SERVICE_ERR, NT_STATUS_UNSUCCESSFUL}, + {PAM_SYSTEM_ERR, NT_STATUS_UNSUCCESSFUL}, + {PAM_BUF_ERR, NT_STATUS_UNSUCCESSFUL}, + {PAM_PERM_DENIED, NT_STATUS_ACCESS_DENIED}, + {PAM_AUTH_ERR, NT_STATUS_WRONG_PASSWORD}, + {PAM_CRED_INSUFFICIENT, NT_STATUS_INSUFFICIENT_LOGON_INFO}, /* FIXME: Is this correct? */ + {PAM_AUTHINFO_UNAVAIL, NT_STATUS_LOGON_FAILURE}, + {PAM_USER_UNKNOWN, NT_STATUS_NO_SUCH_USER}, + {PAM_MAXTRIES, NT_STATUS_REMOTE_SESSION_LIMIT}, /* FIXME: Is this correct? */ + {PAM_NEW_AUTHTOK_REQD, NT_STATUS_PASSWORD_MUST_CHANGE}, + {PAM_ACCT_EXPIRED, NT_STATUS_ACCOUNT_EXPIRED}, + {PAM_SESSION_ERR, NT_STATUS_INSUFFICIENT_RESOURCES}, + {PAM_CRED_UNAVAIL, NT_STATUS_NO_TOKEN}, /* FIXME: Is this correct? */ + {PAM_CRED_EXPIRED, NT_STATUS_PASSWORD_EXPIRED}, /* FIXME: Is this correct? */ + {PAM_CRED_ERR, NT_STATUS_UNSUCCESSFUL}, + {PAM_AUTHTOK_ERR, NT_STATUS_UNSUCCESSFUL}, +#ifdef PAM_AUTHTOK_RECOVER_ERR + {PAM_AUTHTOK_RECOVER_ERR, NT_STATUS_UNSUCCESSFUL}, +#endif + {PAM_AUTHTOK_EXPIRED, NT_STATUS_PASSWORD_EXPIRED}, + {PAM_SUCCESS, NT_STATUS_OK} +}; + +/* NT_STATUS -> PAM map */ +static const struct { + NTSTATUS ntstatus; + int pam_code; +} nt_status_to_pam_map[] = { + {NT_STATUS_UNSUCCESSFUL, PAM_SYSTEM_ERR}, + {NT_STATUS_NO_SUCH_USER, PAM_USER_UNKNOWN}, + {NT_STATUS_WRONG_PASSWORD, PAM_AUTH_ERR}, + {NT_STATUS_LOGON_FAILURE, PAM_AUTH_ERR}, + {NT_STATUS_ACCOUNT_EXPIRED, PAM_ACCT_EXPIRED}, + {NT_STATUS_PASSWORD_EXPIRED, PAM_AUTHTOK_EXPIRED}, + {NT_STATUS_PASSWORD_MUST_CHANGE, PAM_NEW_AUTHTOK_REQD}, + {NT_STATUS_OK, PAM_SUCCESS} +}; + +/***************************************************************************** +convert a PAM error to a NT status32 code + *****************************************************************************/ +NTSTATUS pam_to_nt_status(int pam_error) +{ + int i; + if (pam_error == 0) return NT_STATUS_OK; + + for (i=0; NT_STATUS_V(pam_to_nt_status_map[i].ntstatus); i++) { + if (pam_error == pam_to_nt_status_map[i].pam_code) + return pam_to_nt_status_map[i].ntstatus; + } + return NT_STATUS_UNSUCCESSFUL; +} + +/***************************************************************************** +convert an NT status32 code to a PAM error + *****************************************************************************/ +int nt_status_to_pam(NTSTATUS nt_status) +{ + int i; + if NT_STATUS_IS_OK(nt_status) return PAM_SUCCESS; + + for (i=0; NT_STATUS_V(nt_status_to_pam_map[i].ntstatus); i++) { + if (NT_STATUS_EQUAL(nt_status,nt_status_to_pam_map[i].ntstatus)) + return nt_status_to_pam_map[i].pam_code; + } + return PAM_SYSTEM_ERR; +} + +#else + +/***************************************************************************** +convert a PAM error to a NT status32 code + *****************************************************************************/ +NTSTATUS pam_to_nt_status(int pam_error) +{ + if (pam_error == 0) return NT_STATUS_OK; + return NT_STATUS_UNSUCCESSFUL; +} + +/***************************************************************************** +convert an NT status32 code to a PAM error + *****************************************************************************/ +int nt_status_to_pam(NTSTATUS nt_status) +{ + if (NT_STATUS_EQUAL(nt_status, NT_STATUS_OK)) return 0; + return 4; /* PAM_SYSTEM_ERR */ +} + +#endif + diff --git a/source4/auth/ntlm/pam_errors.h b/source4/auth/ntlm/pam_errors.h new file mode 100644 index 0000000000..904950caa6 --- /dev/null +++ b/source4/auth/ntlm/pam_errors.h @@ -0,0 +1,39 @@ +#ifndef __AUTH_NTLM_PAM_ERRORS_H__ +#define __AUTH_NTLM_PAM_ERRORS_H__ + +#undef _PRINTF_ATTRIBUTE +#define _PRINTF_ATTRIBUTE(a1, a2) PRINTF_ATTRIBUTE(a1, a2) +/* This file was automatically generated by mkproto.pl. DO NOT EDIT */ + +/* this file contains prototypes for functions that are private + * to this subsystem or library. These functions should not be + * used outside this particular subsystem! */ + + +/* The following definitions come from auth/ntlm/pam_errors.c */ + + +/***************************************************************************** +convert a PAM error to a NT status32 code + *****************************************************************************/ +NTSTATUS pam_to_nt_status(int pam_error); + +/***************************************************************************** +convert an NT status32 code to a PAM error + *****************************************************************************/ +int nt_status_to_pam(NTSTATUS nt_status); + +/***************************************************************************** +convert a PAM error to a NT status32 code + *****************************************************************************/ +NTSTATUS pam_to_nt_status(int pam_error); + +/***************************************************************************** +convert an NT status32 code to a PAM error + *****************************************************************************/ +int nt_status_to_pam(NTSTATUS nt_status); +#undef _PRINTF_ATTRIBUTE +#define _PRINTF_ATTRIBUTE(a1, a2) + +#endif /* __AUTH_NTLM_PAM_ERRORS_H__ */ + diff --git a/source4/auth/ntlm_check.c b/source4/auth/ntlm_check.c deleted file mode 100644 index 55f2595f44..0000000000 --- a/source4/auth/ntlm_check.c +++ /dev/null @@ -1,602 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Password and authentication handling - Copyright (C) Andrew Bartlett 2001-2004 - Copyright (C) Gerald Carter 2003 - Copyright (C) Luke Kenneth Casson Leighton 1996-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 3 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, see . -*/ - -#include "includes.h" -#include "lib/crypto/crypto.h" -#include "librpc/gen_ndr/netlogon.h" -#include "libcli/auth/libcli_auth.h" -#include "param/param.h" - -/**************************************************************************** - Core of smb password checking routine. -****************************************************************************/ - -static bool smb_pwd_check_ntlmv1(TALLOC_CTX *mem_ctx, - const DATA_BLOB *nt_response, - const uint8_t *part_passwd, - const DATA_BLOB *sec_blob, - DATA_BLOB *user_sess_key) -{ - /* Finish the encryption of part_passwd. */ - uint8_t p24[24]; - - if (part_passwd == NULL) { - DEBUG(10,("No password set - DISALLOWING access\n")); - /* No password set - always false ! */ - return false; - } - - if (sec_blob->length != 8) { - DEBUG(0, ("smb_pwd_check_ntlmv1: incorrect challenge size (%lu)\n", - (unsigned long)sec_blob->length)); - return false; - } - - if (nt_response->length != 24) { - DEBUG(0, ("smb_pwd_check_ntlmv1: incorrect password length (%lu)\n", - (unsigned long)nt_response->length)); - return false; - } - - SMBOWFencrypt(part_passwd, sec_blob->data, p24); - -#if DEBUG_PASSWORD - DEBUG(100,("Part password (P16) was |\n")); - dump_data(100, part_passwd, 16); - DEBUGADD(100,("Password from client was |\n")); - dump_data(100, nt_response->data, nt_response->length); - DEBUGADD(100,("Given challenge was |\n")); - dump_data(100, sec_blob->data, sec_blob->length); - DEBUGADD(100,("Value from encryption was |\n")); - dump_data(100, p24, 24); -#endif - if (memcmp(p24, nt_response->data, 24) == 0) { - if (user_sess_key != NULL) { - *user_sess_key = data_blob_talloc(mem_ctx, NULL, 16); - SMBsesskeygen_ntv1(part_passwd, user_sess_key->data); - } - return true; - } - return false; -} - -/**************************************************************************** - Core of smb password checking routine. (NTLMv2, LMv2) - Note: The same code works with both NTLMv2 and LMv2. -****************************************************************************/ - -static bool smb_pwd_check_ntlmv2(TALLOC_CTX *mem_ctx, - const DATA_BLOB *ntv2_response, - const uint8_t *part_passwd, - const DATA_BLOB *sec_blob, - const char *user, const char *domain, - bool upper_case_domain, /* should the domain be transformed into upper case? */ - DATA_BLOB *user_sess_key) -{ - /* Finish the encryption of part_passwd. */ - uint8_t kr[16]; - uint8_t value_from_encryption[16]; - DATA_BLOB client_key_data; - - if (part_passwd == NULL) { - DEBUG(10,("No password set - DISALLOWING access\n")); - /* No password set - always false */ - return false; - } - - if (sec_blob->length != 8) { - DEBUG(0, ("smb_pwd_check_ntlmv2: incorrect challenge size (%lu)\n", - (unsigned long)sec_blob->length)); - return false; - } - - if (ntv2_response->length < 24) { - /* We MUST have more than 16 bytes, or the stuff below will go - crazy. No known implementation sends less than the 24 bytes - for LMv2, let alone NTLMv2. */ - DEBUG(0, ("smb_pwd_check_ntlmv2: incorrect password length (%lu)\n", - (unsigned long)ntv2_response->length)); - return false; - } - - client_key_data = data_blob_talloc(mem_ctx, ntv2_response->data+16, ntv2_response->length-16); - /* - todo: should we be checking this for anything? We can't for LMv2, - but for NTLMv2 it is meant to contain the current time etc. - */ - - if (!ntv2_owf_gen(part_passwd, user, domain, upper_case_domain, kr)) { - return false; - } - - SMBOWFencrypt_ntv2(kr, sec_blob, &client_key_data, value_from_encryption); - -#if DEBUG_PASSWORD - DEBUG(100,("Part password (P16) was |\n")); - dump_data(100, part_passwd, 16); - DEBUGADD(100,("Password from client was |\n")); - dump_data(100, ntv2_response->data, ntv2_response->length); - DEBUGADD(100,("Variable data from client was |\n")); - dump_data(100, client_key_data.data, client_key_data.length); - DEBUGADD(100,("Given challenge was |\n")); - dump_data(100, sec_blob->data, sec_blob->length); - DEBUGADD(100,("Value from encryption was |\n")); - dump_data(100, value_from_encryption, 16); -#endif - data_blob_clear_free(&client_key_data); - if (memcmp(value_from_encryption, ntv2_response->data, 16) == 0) { - if (user_sess_key != NULL) { - *user_sess_key = data_blob_talloc(mem_ctx, NULL, 16); - SMBsesskeygen_ntv2(kr, value_from_encryption, user_sess_key->data); - } - return true; - } - return false; -} - -/**************************************************************************** - Core of smb password checking routine. (NTLMv2, LMv2) - Note: The same code works with both NTLMv2 and LMv2. -****************************************************************************/ - -static bool smb_sess_key_ntlmv2(TALLOC_CTX *mem_ctx, - const DATA_BLOB *ntv2_response, - const uint8_t *part_passwd, - const DATA_BLOB *sec_blob, - const char *user, const char *domain, - bool upper_case_domain, /* should the domain be transformed into upper case? */ - DATA_BLOB *user_sess_key) -{ - /* Finish the encryption of part_passwd. */ - uint8_t kr[16]; - uint8_t value_from_encryption[16]; - DATA_BLOB client_key_data; - - if (part_passwd == NULL) { - DEBUG(10,("No password set - DISALLOWING access\n")); - /* No password set - always false */ - return false; - } - - if (sec_blob->length != 8) { - DEBUG(0, ("smb_sess_key_ntlmv2: incorrect challenge size (%lu)\n", - (unsigned long)sec_blob->length)); - return false; - } - - if (ntv2_response->length < 24) { - /* We MUST have more than 16 bytes, or the stuff below will go - crazy. No known implementation sends less than the 24 bytes - for LMv2, let alone NTLMv2. */ - DEBUG(0, ("smb_sess_key_ntlmv2: incorrect password length (%lu)\n", - (unsigned long)ntv2_response->length)); - return false; - } - - client_key_data = data_blob_talloc(mem_ctx, ntv2_response->data+16, ntv2_response->length-16); - - if (!ntv2_owf_gen(part_passwd, user, domain, upper_case_domain, kr)) { - return false; - } - - SMBOWFencrypt_ntv2(kr, sec_blob, &client_key_data, value_from_encryption); - *user_sess_key = data_blob_talloc(mem_ctx, NULL, 16); - SMBsesskeygen_ntv2(kr, value_from_encryption, user_sess_key->data); - return true; -} - -/** - * Compare password hashes against those from the SAM - * - * @param mem_ctx talloc context - * @param client_lanman LANMAN password hash, as supplied by the client - * @param client_nt NT (MD4) password hash, as supplied by the client - * @param username internal Samba username, for log messages - * @param client_username username the client used - * @param client_domain domain name the client used (may be mapped) - * @param stored_lanman LANMAN password hash, as stored on the SAM - * @param stored_nt NT (MD4) password hash, as stored on the SAM - * @param user_sess_key User session key - * @param lm_sess_key LM session key (first 8 bytes of the LM hash) - */ - -NTSTATUS hash_password_check(TALLOC_CTX *mem_ctx, - struct loadparm_context *lp_ctx, - const struct samr_Password *client_lanman, - const struct samr_Password *client_nt, - const char *username, - const struct samr_Password *stored_lanman, - const struct samr_Password *stored_nt) -{ - if (stored_nt == NULL) { - DEBUG(3,("ntlm_password_check: NO NT password stored for user %s.\n", - username)); - } - - if (client_nt && stored_nt) { - if (memcmp(client_nt->hash, stored_nt->hash, sizeof(stored_nt->hash)) == 0) { - return NT_STATUS_OK; - } else { - DEBUG(3,("ntlm_password_check: Interactive logon: NT password check failed for user %s\n", - username)); - return NT_STATUS_WRONG_PASSWORD; - } - - } else if (client_lanman && stored_lanman) { - if (!lp_lanman_auth(lp_ctx)) { - DEBUG(3,("ntlm_password_check: Interactive logon: only LANMAN password supplied for user %s, and LM passwords are disabled!\n", - username)); - return NT_STATUS_WRONG_PASSWORD; - } - if (strchr_m(username, '@')) { - return NT_STATUS_NOT_FOUND; - } - - if (memcmp(client_lanman->hash, stored_lanman->hash, sizeof(stored_lanman->hash)) == 0) { - return NT_STATUS_OK; - } else { - DEBUG(3,("ntlm_password_check: Interactive logon: LANMAN password check failed for user %s\n", - username)); - return NT_STATUS_WRONG_PASSWORD; - } - } - if (strchr_m(username, '@')) { - return NT_STATUS_NOT_FOUND; - } - return NT_STATUS_WRONG_PASSWORD; -} - -/** - * Check a challenge-response password against the value of the NT or - * LM password hash. - * - * @param mem_ctx talloc context - * @param challenge 8-byte challenge. If all zero, forces plaintext comparison - * @param nt_response 'unicode' NT response to the challenge, or unicode password - * @param lm_response ASCII or LANMAN response to the challenge, or password in DOS code page - * @param username internal Samba username, for log messages - * @param client_username username the client used - * @param client_domain domain name the client used (may be mapped) - * @param stored_lanman LANMAN ASCII password from our passdb or similar - * @param stored_nt MD4 unicode password from our passdb or similar - * @param user_sess_key User session key - * @param lm_sess_key LM session key (first 8 bytes of the LM hash) - */ - -NTSTATUS ntlm_password_check(TALLOC_CTX *mem_ctx, - struct loadparm_context *lp_ctx, - uint32_t logon_parameters, - const DATA_BLOB *challenge, - const DATA_BLOB *lm_response, - const DATA_BLOB *nt_response, - const char *username, - const char *client_username, - const char *client_domain, - const struct samr_Password *stored_lanman, - const struct samr_Password *stored_nt, - DATA_BLOB *user_sess_key, - DATA_BLOB *lm_sess_key) -{ - const static uint8_t zeros[8]; - DATA_BLOB tmp_sess_key; - - if (stored_nt == NULL) { - DEBUG(3,("ntlm_password_check: NO NT password stored for user %s.\n", - username)); - } - - *lm_sess_key = data_blob(NULL, 0); - *user_sess_key = data_blob(NULL, 0); - - /* Check for cleartext netlogon. Used by Exchange 5.5. */ - if ((logon_parameters & MSV1_0_CLEARTEXT_PASSWORD_ALLOWED) - && challenge->length == sizeof(zeros) - && (memcmp(challenge->data, zeros, challenge->length) == 0 )) { - struct samr_Password client_nt; - struct samr_Password client_lm; - char *unix_pw = NULL; - bool lm_ok; - - DEBUG(4,("ntlm_password_check: checking plaintext passwords for user %s\n", - username)); - mdfour(client_nt.hash, nt_response->data, nt_response->length); - - if (lm_response->length && - (convert_string_talloc(mem_ctx, lp_iconv_convenience(lp_ctx), CH_DOS, CH_UNIX, - lm_response->data, lm_response->length, - (void **)&unix_pw) != -1)) { - if (E_deshash(unix_pw, client_lm.hash)) { - lm_ok = true; - } else { - lm_ok = false; - } - } else { - lm_ok = false; - } - return hash_password_check(mem_ctx, - lp_ctx, - lm_ok ? &client_lm : NULL, - nt_response->length ? &client_nt : NULL, - username, - stored_lanman, stored_nt); - } - - if (nt_response->length != 0 && nt_response->length < 24) { - DEBUG(2,("ntlm_password_check: invalid NT password length (%lu) for user %s\n", - (unsigned long)nt_response->length, username)); - } - - if (nt_response->length > 24 && stored_nt) { - /* We have the NT MD4 hash challenge available - see if we can - use it - */ - DEBUG(4,("ntlm_password_check: Checking NTLMv2 password with domain [%s]\n", client_domain)); - if (smb_pwd_check_ntlmv2(mem_ctx, - nt_response, - stored_nt->hash, challenge, - client_username, - client_domain, - false, - user_sess_key)) { - *lm_sess_key = *user_sess_key; - if (user_sess_key->length) { - lm_sess_key->length = 8; - } - return NT_STATUS_OK; - } - - DEBUG(4,("ntlm_password_check: Checking NTLMv2 password with uppercased version of domain [%s]\n", client_domain)); - if (smb_pwd_check_ntlmv2(mem_ctx, - nt_response, - stored_nt->hash, challenge, - client_username, - client_domain, - true, - user_sess_key)) { - *lm_sess_key = *user_sess_key; - if (user_sess_key->length) { - lm_sess_key->length = 8; - } - return NT_STATUS_OK; - } - - DEBUG(4,("ntlm_password_check: Checking NTLMv2 password without a domain\n")); - if (smb_pwd_check_ntlmv2(mem_ctx, - nt_response, - stored_nt->hash, challenge, - client_username, - "", - false, - user_sess_key)) { - *lm_sess_key = *user_sess_key; - if (user_sess_key->length) { - lm_sess_key->length = 8; - } - return NT_STATUS_OK; - } else { - DEBUG(3,("ntlm_password_check: NTLMv2 password check failed\n")); - } - } else if (nt_response->length == 24 && stored_nt) { - if (lp_ntlm_auth(lp_ctx)) { - /* We have the NT MD4 hash challenge available - see if we can - use it (ie. does it exist in the smbpasswd file). - */ - DEBUG(4,("ntlm_password_check: Checking NT MD4 password\n")); - if (smb_pwd_check_ntlmv1(mem_ctx, - nt_response, - stored_nt->hash, challenge, - user_sess_key)) { - /* The LM session key for this response is not very secure, - so use it only if we otherwise allow LM authentication */ - - if (lp_lanman_auth(lp_ctx) && stored_lanman) { - *lm_sess_key = data_blob_talloc(mem_ctx, stored_lanman->hash, 8); - } - return NT_STATUS_OK; - } else { - DEBUG(3,("ntlm_password_check: NT MD4 password check failed for user %s\n", - username)); - return NT_STATUS_WRONG_PASSWORD; - } - } else { - DEBUG(2,("ntlm_password_check: NTLMv1 passwords NOT PERMITTED for user %s\n", - username)); - /* no return, becouse we might pick up LMv2 in the LM field */ - } - } - - if (lm_response->length == 0) { - DEBUG(3,("ntlm_password_check: NEITHER LanMan nor NT password supplied for user %s\n", - username)); - return NT_STATUS_WRONG_PASSWORD; - } - - if (lm_response->length < 24) { - DEBUG(2,("ntlm_password_check: invalid LanMan password length (%lu) for user %s\n", - (unsigned long)nt_response->length, username)); - return NT_STATUS_WRONG_PASSWORD; - } - - if (!lp_lanman_auth(lp_ctx)) { - DEBUG(3,("ntlm_password_check: Lanman passwords NOT PERMITTED for user %s\n", - username)); - } else if (!stored_lanman) { - DEBUG(3,("ntlm_password_check: NO LanMan password set for user %s (and no NT password supplied)\n", - username)); - } else if (strchr_m(username, '@')) { - DEBUG(3,("ntlm_password_check: NO LanMan password allowed for username@realm logins (user: %s)\n", - username)); - } else { - DEBUG(4,("ntlm_password_check: Checking LM password\n")); - if (smb_pwd_check_ntlmv1(mem_ctx, - lm_response, - stored_lanman->hash, challenge, - NULL)) { - /* The session key for this response is still very odd. - It not very secure, so use it only if we otherwise - allow LM authentication */ - - if (lp_lanman_auth(lp_ctx) && stored_lanman) { - uint8_t first_8_lm_hash[16]; - memcpy(first_8_lm_hash, stored_lanman->hash, 8); - memset(first_8_lm_hash + 8, '\0', 8); - *user_sess_key = data_blob_talloc(mem_ctx, first_8_lm_hash, 16); - *lm_sess_key = data_blob_talloc(mem_ctx, stored_lanman->hash, 8); - } - return NT_STATUS_OK; - } - } - - if (!stored_nt) { - DEBUG(4,("ntlm_password_check: LM password check failed for user, no NT password %s\n",username)); - return NT_STATUS_WRONG_PASSWORD; - } - - /* This is for 'LMv2' authentication. almost NTLMv2 but limited to 24 bytes. - - related to Win9X, legacy NAS pass-though authentication - */ - DEBUG(4,("ntlm_password_check: Checking LMv2 password with domain %s\n", client_domain)); - if (smb_pwd_check_ntlmv2(mem_ctx, - lm_response, - stored_nt->hash, challenge, - client_username, - client_domain, - false, - &tmp_sess_key)) { - if (nt_response->length > 24) { - /* If NTLMv2 authentication has preceeded us - * (even if it failed), then use the session - * key from that. See the RPC-SAMLOGON - * torture test */ - smb_sess_key_ntlmv2(mem_ctx, - nt_response, - stored_nt->hash, challenge, - client_username, - client_domain, - false, - user_sess_key); - } else { - /* Otherwise, use the LMv2 session key */ - *user_sess_key = tmp_sess_key; - } - *lm_sess_key = *user_sess_key; - if (user_sess_key->length) { - lm_sess_key->length = 8; - } - return NT_STATUS_OK; - } - - DEBUG(4,("ntlm_password_check: Checking LMv2 password with upper-cased version of domain %s\n", client_domain)); - if (smb_pwd_check_ntlmv2(mem_ctx, - lm_response, - stored_nt->hash, challenge, - client_username, - client_domain, - true, - &tmp_sess_key)) { - if (nt_response->length > 24) { - /* If NTLMv2 authentication has preceeded us - * (even if it failed), then use the session - * key from that. See the RPC-SAMLOGON - * torture test */ - smb_sess_key_ntlmv2(mem_ctx, - nt_response, - stored_nt->hash, challenge, - client_username, - client_domain, - true, - user_sess_key); - } else { - /* Otherwise, use the LMv2 session key */ - *user_sess_key = tmp_sess_key; - } - *lm_sess_key = *user_sess_key; - if (user_sess_key->length) { - lm_sess_key->length = 8; - } - return NT_STATUS_OK; - } - - DEBUG(4,("ntlm_password_check: Checking LMv2 password without a domain\n")); - if (smb_pwd_check_ntlmv2(mem_ctx, - lm_response, - stored_nt->hash, challenge, - client_username, - "", - false, - &tmp_sess_key)) { - if (nt_response->length > 24) { - /* If NTLMv2 authentication has preceeded us - * (even if it failed), then use the session - * key from that. See the RPC-SAMLOGON - * torture test */ - smb_sess_key_ntlmv2(mem_ctx, - nt_response, - stored_nt->hash, challenge, - client_username, - "", - false, - user_sess_key); - } else { - /* Otherwise, use the LMv2 session key */ - *user_sess_key = tmp_sess_key; - } - *lm_sess_key = *user_sess_key; - if (user_sess_key->length) { - lm_sess_key->length = 8; - } - return NT_STATUS_OK; - } - - /* Apparently NT accepts NT responses in the LM field - - I think this is related to Win9X pass-though authentication - */ - DEBUG(4,("ntlm_password_check: Checking NT MD4 password in LM field\n")); - if (lp_ntlm_auth(lp_ctx)) { - if (smb_pwd_check_ntlmv1(mem_ctx, - lm_response, - stored_nt->hash, challenge, - NULL)) { - /* The session key for this response is still very odd. - It not very secure, so use it only if we otherwise - allow LM authentication */ - - if (lp_lanman_auth(lp_ctx) && stored_lanman) { - uint8_t first_8_lm_hash[16]; - memcpy(first_8_lm_hash, stored_lanman->hash, 8); - memset(first_8_lm_hash + 8, '\0', 8); - *user_sess_key = data_blob_talloc(mem_ctx, first_8_lm_hash, 16); - *lm_sess_key = data_blob_talloc(mem_ctx, stored_lanman->hash, 8); - } - return NT_STATUS_OK; - } - DEBUG(3,("ntlm_password_check: LM password, NT MD4 password in LM field and LMv2 failed for user %s\n",username)); - } else { - DEBUG(3,("ntlm_password_check: LM password and LMv2 failed for user %s, and NT MD4 password in LM field not permitted\n",username)); - } - - /* Try and match error codes */ - if (strchr_m(username, '@')) { - return NT_STATUS_NOT_FOUND; - } - return NT_STATUS_WRONG_PASSWORD; -} - diff --git a/source4/auth/pam_errors.c b/source4/auth/pam_errors.c deleted file mode 100644 index 9774ad8727..0000000000 --- a/source4/auth/pam_errors.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * PAM error mapping functions - * 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 3 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, see . - */ - -#include "includes.h" - -#ifdef WITH_HAVE_SECURITY_PAM_APPL_H -#include - -#if defined(PAM_AUTHTOK_RECOVERY_ERR) && !defined(PAM_AUTHTOK_RECOVER_ERR) -#define PAM_AUTHTOK_RECOVER_ERR PAM_AUTHTOK_RECOVERY_ERR -#endif - -/* PAM -> NT_STATUS map */ -static const struct { - int pam_code; - NTSTATUS ntstatus; -} pam_to_nt_status_map[] = { - {PAM_OPEN_ERR, NT_STATUS_UNSUCCESSFUL}, - {PAM_SYMBOL_ERR, NT_STATUS_UNSUCCESSFUL}, - {PAM_SERVICE_ERR, NT_STATUS_UNSUCCESSFUL}, - {PAM_SYSTEM_ERR, NT_STATUS_UNSUCCESSFUL}, - {PAM_BUF_ERR, NT_STATUS_UNSUCCESSFUL}, - {PAM_PERM_DENIED, NT_STATUS_ACCESS_DENIED}, - {PAM_AUTH_ERR, NT_STATUS_WRONG_PASSWORD}, - {PAM_CRED_INSUFFICIENT, NT_STATUS_INSUFFICIENT_LOGON_INFO}, /* FIXME: Is this correct? */ - {PAM_AUTHINFO_UNAVAIL, NT_STATUS_LOGON_FAILURE}, - {PAM_USER_UNKNOWN, NT_STATUS_NO_SUCH_USER}, - {PAM_MAXTRIES, NT_STATUS_REMOTE_SESSION_LIMIT}, /* FIXME: Is this correct? */ - {PAM_NEW_AUTHTOK_REQD, NT_STATUS_PASSWORD_MUST_CHANGE}, - {PAM_ACCT_EXPIRED, NT_STATUS_ACCOUNT_EXPIRED}, - {PAM_SESSION_ERR, NT_STATUS_INSUFFICIENT_RESOURCES}, - {PAM_CRED_UNAVAIL, NT_STATUS_NO_TOKEN}, /* FIXME: Is this correct? */ - {PAM_CRED_EXPIRED, NT_STATUS_PASSWORD_EXPIRED}, /* FIXME: Is this correct? */ - {PAM_CRED_ERR, NT_STATUS_UNSUCCESSFUL}, - {PAM_AUTHTOK_ERR, NT_STATUS_UNSUCCESSFUL}, -#ifdef PAM_AUTHTOK_RECOVER_ERR - {PAM_AUTHTOK_RECOVER_ERR, NT_STATUS_UNSUCCESSFUL}, -#endif - {PAM_AUTHTOK_EXPIRED, NT_STATUS_PASSWORD_EXPIRED}, - {PAM_SUCCESS, NT_STATUS_OK} -}; - -/* NT_STATUS -> PAM map */ -static const struct { - NTSTATUS ntstatus; - int pam_code; -} nt_status_to_pam_map[] = { - {NT_STATUS_UNSUCCESSFUL, PAM_SYSTEM_ERR}, - {NT_STATUS_NO_SUCH_USER, PAM_USER_UNKNOWN}, - {NT_STATUS_WRONG_PASSWORD, PAM_AUTH_ERR}, - {NT_STATUS_LOGON_FAILURE, PAM_AUTH_ERR}, - {NT_STATUS_ACCOUNT_EXPIRED, PAM_ACCT_EXPIRED}, - {NT_STATUS_PASSWORD_EXPIRED, PAM_AUTHTOK_EXPIRED}, - {NT_STATUS_PASSWORD_MUST_CHANGE, PAM_NEW_AUTHTOK_REQD}, - {NT_STATUS_OK, PAM_SUCCESS} -}; - -/***************************************************************************** -convert a PAM error to a NT status32 code - *****************************************************************************/ -NTSTATUS pam_to_nt_status(int pam_error) -{ - int i; - if (pam_error == 0) return NT_STATUS_OK; - - for (i=0; NT_STATUS_V(pam_to_nt_status_map[i].ntstatus); i++) { - if (pam_error == pam_to_nt_status_map[i].pam_code) - return pam_to_nt_status_map[i].ntstatus; - } - return NT_STATUS_UNSUCCESSFUL; -} - -/***************************************************************************** -convert an NT status32 code to a PAM error - *****************************************************************************/ -int nt_status_to_pam(NTSTATUS nt_status) -{ - int i; - if NT_STATUS_IS_OK(nt_status) return PAM_SUCCESS; - - for (i=0; NT_STATUS_V(nt_status_to_pam_map[i].ntstatus); i++) { - if (NT_STATUS_EQUAL(nt_status,nt_status_to_pam_map[i].ntstatus)) - return nt_status_to_pam_map[i].pam_code; - } - return PAM_SYSTEM_ERR; -} - -#else - -/***************************************************************************** -convert a PAM error to a NT status32 code - *****************************************************************************/ -NTSTATUS pam_to_nt_status(int pam_error) -{ - if (pam_error == 0) return NT_STATUS_OK; - return NT_STATUS_UNSUCCESSFUL; -} - -/***************************************************************************** -convert an NT status32 code to a PAM error - *****************************************************************************/ -int nt_status_to_pam(NTSTATUS nt_status) -{ - if (NT_STATUS_EQUAL(nt_status, NT_STATUS_OK)) return 0; - return 4; /* PAM_SYSTEM_ERR */ -} - -#endif - diff --git a/source4/utils/config.mk b/source4/utils/config.mk index a7d82684e4..13f3b0a145 100644 --- a/source4/utils/config.mk +++ b/source4/utils/config.mk @@ -13,6 +13,7 @@ PRIVATE_DEPENDENCIES = \ gensec \ LIBCLI_RESOLVE \ auth \ + ntlm_check \ MESSAGING \ LIBEVENTS # End BINARY ntlm_auth diff --git a/source4/utils/ntlm_auth.c b/source4/utils/ntlm_auth.c index 07c0e4f31e..95029deffa 100644 --- a/source4/utils/ntlm_auth.c +++ b/source4/utils/ntlm_auth.c @@ -30,6 +30,7 @@ #include "auth/auth.h" #include "librpc/gen_ndr/ndr_netlogon.h" #include "auth/auth_sam.h" +#include "auth/ntlm/ntlm_check.h" #include "pstring.h" #include "libcli/auth/libcli_auth.h" #include "libcli/security/security.h" -- cgit From 714b3a87d2ac21d4d6b7b64d32332487308c6002 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 5 May 2008 19:28:38 +1000 Subject: Fix the build after the auth/ -> auth/ntlm/ rename I need to fix up the header inclusion, but this fixes things for now. Andrew Bartlett (This used to be commit 7c07edb24b31e7dc3e9b836ec4a6680ee2b04276) --- source4/auth/ntlm/auth.c | 2 +- source4/auth/ntlm/auth_anonymous.c | 2 +- source4/auth/ntlm/auth_developer.c | 2 +- source4/auth/ntlm/auth_server.c | 2 +- source4/auth/ntlm/auth_unix.c | 2 +- source4/auth/ntlm/auth_winbind.c | 2 +- source4/auth/ntlmssp/ntlmssp.c | 2 +- source4/auth/ntlmssp/ntlmssp_server.c | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/source4/auth/ntlm/auth.c b/source4/auth/ntlm/auth.c index b74a438962..dc4303dd5c 100644 --- a/source4/auth/ntlm/auth.c +++ b/source4/auth/ntlm/auth.c @@ -21,7 +21,7 @@ #include "includes.h" #include "lib/util/dlinklist.h" #include "auth/auth.h" -#include "auth/auth_proto.h" +#include "auth/ntlm/auth_proto.h" #include "lib/events/events.h" #include "build.h" #include "param/param.h" diff --git a/source4/auth/ntlm/auth_anonymous.c b/source4/auth/ntlm/auth_anonymous.c index b93c7c2008..c889071878 100644 --- a/source4/auth/ntlm/auth_anonymous.c +++ b/source4/auth/ntlm/auth_anonymous.c @@ -21,7 +21,7 @@ #include "includes.h" #include "auth/auth.h" -#include "auth/auth_proto.h" +#include "auth/ntlm/auth_proto.h" #include "param/param.h" /** diff --git a/source4/auth/ntlm/auth_developer.c b/source4/auth/ntlm/auth_developer.c index a2c9cbc828..3b8c83c349 100644 --- a/source4/auth/ntlm/auth_developer.c +++ b/source4/auth/ntlm/auth_developer.c @@ -21,7 +21,7 @@ #include "includes.h" #include "auth/auth.h" -#include "auth/auth_proto.h" +#include "auth/ntlm/auth_proto.h" #include "libcli/security/security.h" #include "librpc/gen_ndr/ndr_samr.h" diff --git a/source4/auth/ntlm/auth_server.c b/source4/auth/ntlm/auth_server.c index be5f84fe39..f154cf0425 100644 --- a/source4/auth/ntlm/auth_server.c +++ b/source4/auth/ntlm/auth_server.c @@ -21,7 +21,7 @@ #include "includes.h" #include "auth/auth.h" -#include "auth/auth_proto.h" +#include "auth/ntlm/auth_proto.h" #include "auth/credentials/credentials.h" #include "libcli/security/security.h" #include "librpc/gen_ndr/ndr_samr.h" diff --git a/source4/auth/ntlm/auth_unix.c b/source4/auth/ntlm/auth_unix.c index a417107025..5073ba6461 100644 --- a/source4/auth/ntlm/auth_unix.c +++ b/source4/auth/ntlm/auth_unix.c @@ -21,7 +21,7 @@ #include "includes.h" #include "auth/auth.h" -#include "auth/auth_proto.h" +#include "auth/ntlm/auth_proto.h" #include "system/passwd.h" /* needed by some systems for struct passwd */ #include "lib/socket/socket.h" #include "auth/pam_errors.h" diff --git a/source4/auth/ntlm/auth_winbind.c b/source4/auth/ntlm/auth_winbind.c index 149f549afa..ac63b242e4 100644 --- a/source4/auth/ntlm/auth_winbind.c +++ b/source4/auth/ntlm/auth_winbind.c @@ -23,7 +23,7 @@ #include "includes.h" #include "auth/auth.h" -#include "auth/auth_proto.h" +#include "auth/ntlm/auth_proto.h" #include "auth/session_proto.h" #include "nsswitch/winbind_client.h" #include "librpc/gen_ndr/ndr_netlogon.h" diff --git a/source4/auth/ntlmssp/ntlmssp.c b/source4/auth/ntlmssp/ntlmssp.c index 64bfebd3d1..0b7f0da9af 100644 --- a/source4/auth/ntlmssp/ntlmssp.c +++ b/source4/auth/ntlmssp/ntlmssp.c @@ -29,7 +29,7 @@ #include "auth/gensec/gensec.h" #include "auth/gensec/gensec_proto.h" #include "auth/auth.h" -#include "auth/auth_proto.h" +#include "auth/ntlm/auth_proto.h" #include "param/param.h" /** diff --git a/source4/auth/ntlmssp/ntlmssp_server.c b/source4/auth/ntlmssp/ntlmssp_server.c index d8ef2a20b8..dfc5940d99 100644 --- a/source4/auth/ntlmssp/ntlmssp_server.c +++ b/source4/auth/ntlmssp/ntlmssp_server.c @@ -30,7 +30,7 @@ #include "auth/credentials/credentials.h" #include "auth/gensec/gensec.h" #include "auth/auth.h" -#include "auth/auth_proto.h" +#include "auth/ntlm/auth_proto.h" #include "param/param.h" #include "auth/session_proto.h" -- cgit From 674d089beac8a5808a4537b8021e466c4c14f656 Mon Sep 17 00:00:00 2001 From: Tiago Batista Date: Tue, 6 May 2008 08:12:03 +1000 Subject: Tiago Batista posted a patch to fix the build: Trying to compile the latest git tree, I got some errors "auth/pam_error.h not found" errors, it looks like it moved to auth/ntlm/pam_errors.h. Andrew Bartlett (This used to be commit 95831a015ae076b52256961f771f50dd9b278e33) --- source4/auth/ntlm/auth_unix.c | 2 +- source4/torture/winbind/struct_based.c | 2 +- source4/winbind/wb_samba3_cmd.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source4/auth/ntlm/auth_unix.c b/source4/auth/ntlm/auth_unix.c index 5073ba6461..1717b9d0e1 100644 --- a/source4/auth/ntlm/auth_unix.c +++ b/source4/auth/ntlm/auth_unix.c @@ -24,7 +24,7 @@ #include "auth/ntlm/auth_proto.h" #include "system/passwd.h" /* needed by some systems for struct passwd */ #include "lib/socket/socket.h" -#include "auth/pam_errors.h" +#include "auth/ntlm/pam_errors.h" #include "param/param.h" /* TODO: look at how to best fill in parms retrieveing a struct passwd info diff --git a/source4/torture/winbind/struct_based.c b/source4/torture/winbind/struct_based.c index 87378aadb8..31c5b8cf96 100644 --- a/source4/torture/winbind/struct_based.c +++ b/source4/torture/winbind/struct_based.c @@ -26,7 +26,7 @@ #include "libcli/security/security.h" #include "librpc/gen_ndr/netlogon.h" #include "param/param.h" -#include "auth/pam_errors.h" +#include "auth/ntlm/pam_errors.h" #define DO_STRUCT_REQ_REP_EXT(op,req,rep,expected,strict,warnaction,cmt) do { \ NSS_STATUS __got, __expected = (expected); \ diff --git a/source4/winbind/wb_samba3_cmd.c b/source4/winbind/wb_samba3_cmd.c index f0aaaa7778..5ef0339ecb 100644 --- a/source4/winbind/wb_samba3_cmd.c +++ b/source4/winbind/wb_samba3_cmd.c @@ -29,7 +29,7 @@ #include "version.h" #include "librpc/gen_ndr/netlogon.h" #include "libcli/security/security.h" -#include "auth/pam_errors.h" +#include "auth/ntlm/pam_errors.h" #include "auth/credentials/credentials.h" #include "smbd/service_task.h" -- cgit From f51a79889c769f0a30eef5bd8a486e08c6bbdad2 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 6 May 2008 12:38:55 +0200 Subject: libreplace: check how portable utimes() and futimes() are metze (This used to be commit 8798ce3c744025b94973784dcb44d099427ef190) --- source4/lib/replace/system/config.m4 | 1 + 1 file changed, 1 insertion(+) diff --git a/source4/lib/replace/system/config.m4 b/source4/lib/replace/system/config.m4 index 66c2bd652a..ae26bb5590 100644 --- a/source4/lib/replace/system/config.m4 +++ b/source4/lib/replace/system/config.m4 @@ -9,6 +9,7 @@ AC_CHECK_HEADERS(sys/select.h) # time AC_CHECK_HEADERS(sys/time.h utime.h) AC_HEADER_TIME +AC_CHECK_FUNCS(utime utimes futimes) # wait AC_HEADER_SYS_WAIT -- cgit From 42059c7e7665833e0116dc4e1e9aa948726ec816 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Tue, 6 May 2008 15:26:37 +0200 Subject: torture: use dom_idx after determining it in samba3rpc.c:get_usr_handle() Michael (This used to be commit 334d76c3559870bd9dc9ef55c9b1a7ce21ee9d4c) --- source4/torture/rpc/samba3rpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/torture/rpc/samba3rpc.c b/source4/torture/rpc/samba3rpc.c index 1103acaefa..17342f9b86 100644 --- a/source4/torture/rpc/samba3rpc.c +++ b/source4/torture/rpc/samba3rpc.c @@ -426,7 +426,7 @@ static NTSTATUS get_usr_handle(struct smbcli_state *cli, "builtin") ? 1:0; l.in.connect_handle = &conn_handle; - domain_name.string = enumdom.out.sam->entries[0].name.string; + domain_name.string = enumdom.out.sam->entries[dom_idx].name.string; *domain = talloc_strdup(mem_ctx, domain_name.string); l.in.domain_name = &domain_name; -- cgit From 387c17685c4455bceeea35dd50ce25d593f8892a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 7 May 2008 08:59:06 +0200 Subject: build: fix path to lex_compile.sh metze (This used to be commit 6a1b7f56afa7475880f4eb5f0b669fd2b95a1d8f) --- source4/build/make/rules.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/build/make/rules.mk b/source4/build/make/rules.mk index 8c5b1fe6f3..1fc5e23569 100644 --- a/source4/build/make/rules.mk +++ b/source4/build/make/rules.mk @@ -234,7 +234,7 @@ include/includes.d: include/includes.h .l.c: @echo "Building $< with $(LEX)" - @-$(make_utility_dir)/script/lex_compile.sh "$(LEX)" "$<" "$@" + @-$(make_utility_dir)/lex_compile.sh "$(LEX)" "$<" "$@" %.a: @echo Linking $@ -- cgit From bbf4ce91462598cee1eebfb94a773194e56a7ff8 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 7 May 2008 13:10:31 +0200 Subject: libreplace: always provide utime() and utimes() I'd like to also provide futimes(), but it seems that some systems doesn't support a it at kernel level. If someone knows how to write a portable replacement for futimes() please tell me... metze (This used to be commit a9604fe4a323dccb537cf02ea7594437b4995803) --- source4/lib/replace/README | 2 + source4/lib/replace/replace.c | 27 +++++++ source4/lib/replace/replace.h | 10 +++ source4/lib/replace/system/config.m4 | 2 +- source4/lib/replace/system/time.h | 15 ++++ source4/lib/replace/test/testsuite.c | 145 +++++++++++++++++++++++++++++++++++ 6 files changed, 200 insertions(+), 1 deletion(-) diff --git a/source4/lib/replace/README b/source4/lib/replace/README index 43f7b08572..4d94317c4b 100644 --- a/source4/lib/replace/README +++ b/source4/lib/replace/README @@ -62,6 +62,8 @@ getnameinfo gai_strerror getifaddrs freeifaddrs +utime +utimes Types: bool diff --git a/source4/lib/replace/replace.c b/source4/lib/replace/replace.c index 443da2ab24..2c3f14c2df 100644 --- a/source4/lib/replace/replace.c +++ b/source4/lib/replace/replace.c @@ -584,3 +584,30 @@ int rep_unsetenv(const char *name) return 0; } #endif + +#ifndef HAVE_UTIME +int rep_utime(const char *filename, const struct utimbuf *buf) +{ + errno = ENOSYS; + return -1; +} +#endif + +#ifndef HAVE_UTIMES +int rep_utimes(const char *filename, const struct timeval tv[2]) +{ + struct utimbuf u; + + u.actime = tv[0].tv_sec; + if (tv[0].tv_usec > 500000) { + u.actime += 1; + } + + u.modtime = tv[1].tv_sec; + if (tv[1].tv_usec > 500000) { + u.modtime += 1; + } + + return utime(filename, &u); +} +#endif diff --git a/source4/lib/replace/replace.h b/source4/lib/replace/replace.h index bf95169352..c69ea6cdac 100644 --- a/source4/lib/replace/replace.h +++ b/source4/lib/replace/replace.h @@ -101,6 +101,16 @@ void *rep_memmove(void *dest,const void *src,int size); /* prototype is in "system/time.h" */ #endif +#ifndef HAVE_UTIME +#define utime rep_utime +/* prototype is in "system/time.h" */ +#endif + +#ifndef HAVE_UTIMES +#define utimes rep_utimes +/* prototype is in "system/time.h" */ +#endif + #ifndef HAVE_STRLCPY #define strlcpy rep_strlcpy size_t rep_strlcpy(char *d, const char *s, size_t bufsize); diff --git a/source4/lib/replace/system/config.m4 b/source4/lib/replace/system/config.m4 index ae26bb5590..5c9b53d5c5 100644 --- a/source4/lib/replace/system/config.m4 +++ b/source4/lib/replace/system/config.m4 @@ -9,7 +9,7 @@ AC_CHECK_HEADERS(sys/select.h) # time AC_CHECK_HEADERS(sys/time.h utime.h) AC_HEADER_TIME -AC_CHECK_FUNCS(utime utimes futimes) +AC_CHECK_FUNCS(utime utimes) # wait AC_HEADER_SYS_WAIT diff --git a/source4/lib/replace/system/time.h b/source4/lib/replace/system/time.h index 036812ab8f..4abf295d1a 100644 --- a/source4/lib/replace/system/time.h +++ b/source4/lib/replace/system/time.h @@ -39,6 +39,11 @@ #ifdef HAVE_UTIME_H #include +#else +struct utimbuf { + time_t actime; /* access time */ + time_t modtime; /* modification time */ +}; #endif #ifndef HAVE_MKTIME @@ -51,4 +56,14 @@ time_t rep_mktime(struct tm *t); time_t rep_timegm(struct tm *tm); #endif +#ifndef HAVE_UTIME +/* define is in "replace.h" */ +int rep_utime(const char *filename, const struct utimbuf *buf); +#endif + +#ifndef HAVE_UTIMES +/* define is in "replace.h" */ +int rep_utimes(const char *filename, const struct timeval tv[2]); +#endif + #endif diff --git a/source4/lib/replace/test/testsuite.c b/source4/lib/replace/test/testsuite.c index b538360365..1e8290906e 100644 --- a/source4/lib/replace/test/testsuite.c +++ b/source4/lib/replace/test/testsuite.c @@ -872,6 +872,149 @@ static int test_getifaddrs(void) return true; } +static int test_utime(void) +{ + struct utimbuf u; + struct stat st1, st2, st3; + int fd; + + printf("test: utime\n"); + unlink(TESTFILE); + + fd = open(TESTFILE, O_RDWR|O_CREAT, 0600); + if (fd == -1) { + printf("failure: utime [\n" + "creating '%s' failed - %s\n]\n", + TESTFILE, strerror(errno)); + return false; + } + + if (fstat(fd, &st1) != 0) { + printf("failure: utime [\n" + "fstat (1) failed - %s\n]\n", + strerror(errno)); + return false; + } + + u.actime = st1.st_atime + 300; + u.modtime = st1.st_mtime - 300; + if (utime(TESTFILE, &u) != 0) { + printf("failure: utime [\n" + "utime(&u) failed - %s\n]\n", + strerror(errno)); + return false; + } + + if (fstat(fd, &st2) != 0) { + printf("failure: utime [\n" + "fstat (2) failed - %s\n]\n", + strerror(errno)); + return false; + } + + if (utime(TESTFILE, NULL) != 0) { + printf("failure: utime [\n" + "utime(NULL) failed - %s\n]\n", + strerror(errno)); + return false; + } + + if (fstat(fd, &st3) != 0) { + printf("failure: utime [\n" + "fstat (3) failed - %s\n]\n", + strerror(errno)); + return false; + } + +#define CMP_VAL(a,c,b) do { \ + if (a c b) { \ + printf("failure: utime [\n" \ + "%s: %s(%d) %s %s(%d)\n]\n", \ + __location__, \ + #a, (int)a, #c, #b, (int)b); \ + return false; \ + } \ +} while(0) +#define EQUAL_VAL(a,b) CMP_VAL(a,!=,b) +#define GREATER_VAL(a,b) CMP_VAL(a,<=,b) +#define LESSER_VAL(a,b) CMP_VAL(a,>=,b) + + EQUAL_VAL(st2.st_atime, st1.st_atime + 300); + EQUAL_VAL(st2.st_mtime, st1.st_mtime - 300); + LESSER_VAL(st3.st_atime, st2.st_atime); + GREATER_VAL(st3.st_mtime, st2.st_mtime); + +#undef CMP_VAL +#undef EQUAL_VAL +#undef GREATER_VAL +#undef LESSER_VAL + + unlink(TESTFILE); + printf("success: utime\n"); + return true; +} + +static int test_utimes(void) +{ + struct timeval tv[2]; + struct stat st1, st2; + int fd; + + printf("test: utimes\n"); + unlink(TESTFILE); + + fd = open(TESTFILE, O_RDWR|O_CREAT, 0600); + if (fd == -1) { + printf("failure: utimes [\n" + "creating '%s' failed - %s\n]\n", + TESTFILE, strerror(errno)); + return false; + } + + if (fstat(fd, &st1) != 0) { + printf("failure: utimes [\n" + "fstat (1) failed - %s\n]\n", + strerror(errno)); + return false; + } + + ZERO_STRUCT(tv); + tv[0].tv_sec = st1.st_atime + 300; + tv[1].tv_sec = st1.st_mtime - 300; + if (utimes(TESTFILE, tv) != 0) { + printf("failure: utimes [\n" + "utimes(tv) failed - %s\n]\n", + strerror(errno)); + return false; + } + + if (fstat(fd, &st2) != 0) { + printf("failure: utimes [\n" + "fstat (2) failed - %s\n]\n", + strerror(errno)); + return false; + } + +#define EQUAL_VAL(a,b) do { \ + if (a != b) { \ + printf("failure: utimes [\n" \ + "%s: %s(%d) != %s(%d)\n]\n", \ + __location__, \ + #a, (int)a, #b, (int)b); \ + return false; \ + } \ +} while(0) + + EQUAL_VAL(st2.st_atime, st1.st_atime + 300); + EQUAL_VAL(st2.st_mtime, st1.st_mtime - 300); + +#undef EQUAL_VAL + + unlink(TESTFILE); + printf("success: utimes\n"); + return true; +} + struct torture_context; bool torture_local_replace(struct torture_context *ctx) { @@ -920,6 +1063,8 @@ bool torture_local_replace(struct torture_context *ctx) ret &= test_socketpair(); ret &= test_strptime(); ret &= test_getifaddrs(); + ret &= test_utime(); + ret &= test_utimes(); return ret; } -- cgit From 3e80085fb09a89957991780f79f5726029b8a26f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 7 May 2008 15:46:22 +0200 Subject: pvfs: remove XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME code I'll fix this more correctly very soon, so that we'll pass the BASE-DELAYWRITE test. metze (This used to be commit b09dd6b65d533832a025a51509dcc84f84b048aa) --- source4/librpc/idl/xattr.idl | 12 +++++++++--- source4/ntvfs/posix/pvfs_open.c | 17 ----------------- source4/ntvfs/posix/pvfs_setfileinfo.c | 2 -- source4/ntvfs/posix/pvfs_xattr.c | 32 +++++++++++++++----------------- source4/ntvfs/posix/vfs_posix.h | 3 --- 5 files changed, 24 insertions(+), 42 deletions(-) diff --git a/source4/librpc/idl/xattr.idl b/source4/librpc/idl/xattr.idl index 7e73baee7d..2010d51ce1 100644 --- a/source4/librpc/idl/xattr.idl +++ b/source4/librpc/idl/xattr.idl @@ -31,8 +31,14 @@ interface xattr NTTIME change_time; } xattr_DosInfo1; - const int XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME = 0x1; +/* + We use xattrDosInfo1 again when we store values. + Because the sticky write time is now stored in the opendb + and xattr_DosInfo2Old is only present to parse existing + values from disk. + const int XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME = 0x1; +*/ typedef struct { uint32 flags; uint32 attrib; @@ -43,11 +49,11 @@ interface xattr NTTIME change_time; NTTIME write_time; /* only used when sticky write time is set */ utf8string name; - } xattr_DosInfo2; + } xattr_DosInfo2Old; typedef [switch_type(uint16)] union { [case(1)] xattr_DosInfo1 info1; - [case(2)] xattr_DosInfo2 info2; + [case(2)] xattr_DosInfo2Old oldinfo2; } xattr_DosInfo; typedef [public] struct { diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c index 6e77cb7c75..c9c1c56f14 100644 --- a/source4/ntvfs/posix/pvfs_open.c +++ b/source4/ntvfs/posix/pvfs_open.c @@ -262,7 +262,6 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs, f->handle->position = 0; f->handle->mode = 0; f->handle->oplock = NULL; - f->handle->sticky_write_time = false; f->handle->open_completed = false; if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) && @@ -416,16 +415,6 @@ cleanup_delete: */ static int pvfs_handle_destructor(struct pvfs_file_handle *h) { - /* the write time is no longer sticky */ - if (h->sticky_write_time) { - NTSTATUS status; - status = pvfs_dosattrib_load(h->pvfs, h->name, h->fd); - if (NT_STATUS_IS_OK(status)) { - h->name->dos.flags &= ~XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME; - pvfs_dosattrib_save(h->pvfs, h->name, h->fd); - } - } - if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) && h->name->stream_name) { NTSTATUS status; @@ -707,7 +696,6 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, f->handle->mode = 0; f->handle->oplock = NULL; f->handle->have_opendb_entry = true; - f->handle->sticky_write_time = false; f->handle->open_completed = false; status = odb_open_file(lck, f->handle, name->full_name, @@ -1257,7 +1245,6 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, f->handle->mode = 0; f->handle->oplock = NULL; f->handle->have_opendb_entry = false; - f->handle->sticky_write_time = false; f->handle->open_completed = false; /* form the lock context used for byte range locking and @@ -1479,10 +1466,6 @@ NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs, unix_times.actime = 0; unix_times.modtime = io->close.in.write_time; utime(f->handle->name->full_name, &unix_times); - } else if (f->handle->sticky_write_time) { - unix_times.actime = 0; - unix_times.modtime = nt_time_to_unix(f->handle->name->dos.write_time); - utime(f->handle->name->full_name, &unix_times); } talloc_free(f); diff --git a/source4/ntvfs/posix/pvfs_setfileinfo.c b/source4/ntvfs/posix/pvfs_setfileinfo.c index ad47fe90c9..0beca75ead 100644 --- a/source4/ntvfs/posix/pvfs_setfileinfo.c +++ b/source4/ntvfs/posix/pvfs_setfileinfo.c @@ -342,8 +342,6 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs, } if (!null_nttime(info->basic_info.in.write_time)) { newstats.dos.write_time = info->basic_info.in.write_time; - newstats.dos.flags |= XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME; - h->sticky_write_time = true; } if (!null_nttime(info->basic_info.in.change_time)) { newstats.dos.change_time = info->basic_info.in.change_time; diff --git a/source4/ntvfs/posix/pvfs_xattr.c b/source4/ntvfs/posix/pvfs_xattr.c index 3043b80538..3cbbcbe92f 100644 --- a/source4/ntvfs/posix/pvfs_xattr.c +++ b/source4/ntvfs/posix/pvfs_xattr.c @@ -162,7 +162,7 @@ NTSTATUS pvfs_dosattrib_load(struct pvfs_state *pvfs, struct pvfs_filename *name struct xattr_DosAttrib attrib; TALLOC_CTX *mem_ctx = talloc_new(name); struct xattr_DosInfo1 *info1; - struct xattr_DosInfo2 *info2; + struct xattr_DosInfo2Old *info2; if (name->stream_name != NULL) { name->stream_exists = false; @@ -210,7 +210,11 @@ NTSTATUS pvfs_dosattrib_load(struct pvfs_state *pvfs, struct pvfs_filename *name break; case 2: - info2 = &attrib.info.info2; + /* + * Note: This is only used to parse existing values from disk + * We use xattr_DosInfo1 again for storing new values + */ + info2 = &attrib.info.oldinfo2; name->dos.attrib = pvfs_attrib_normalise(info2->attrib, name->st.st_mode); name->dos.ea_size = info2->ea_size; @@ -225,9 +229,6 @@ NTSTATUS pvfs_dosattrib_load(struct pvfs_state *pvfs, struct pvfs_filename *name name->dos.change_time = info2->change_time; } name->dos.flags = info2->flags; - if (name->dos.flags & XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME) { - name->dos.write_time = info2->write_time; - } break; default: @@ -250,26 +251,23 @@ NTSTATUS pvfs_dosattrib_load(struct pvfs_state *pvfs, struct pvfs_filename *name NTSTATUS pvfs_dosattrib_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd) { struct xattr_DosAttrib attrib; - struct xattr_DosInfo2 *info2; + struct xattr_DosInfo1 *info1; if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) { return NT_STATUS_OK; } - attrib.version = 2; - info2 = &attrib.info.info2; + attrib.version = 1; + info1 = &attrib.info.info1; name->dos.attrib = pvfs_attrib_normalise(name->dos.attrib, name->st.st_mode); - info2->attrib = name->dos.attrib; - info2->ea_size = name->dos.ea_size; - info2->size = name->st.st_size; - info2->alloc_size = name->dos.alloc_size; - info2->create_time = name->dos.create_time; - info2->change_time = name->dos.change_time; - info2->write_time = name->dos.write_time; - info2->flags = name->dos.flags; - info2->name = ""; + info1->attrib = name->dos.attrib; + info1->ea_size = name->dos.ea_size; + info1->size = name->st.st_size; + info1->alloc_size = name->dos.alloc_size; + info1->create_time = name->dos.create_time; + info1->change_time = name->dos.change_time; return pvfs_xattr_ndr_save(pvfs, name->full_name, fd, XATTR_DOSATTRIB_NAME, &attrib, diff --git a/source4/ntvfs/posix/vfs_posix.h b/source4/ntvfs/posix/vfs_posix.h index 441424142f..c194698b64 100644 --- a/source4/ntvfs/posix/vfs_posix.h +++ b/source4/ntvfs/posix/vfs_posix.h @@ -169,9 +169,6 @@ struct pvfs_file_handle { /* we need this hook back to our parent for lock destruction */ struct pvfs_state *pvfs; - /* have we set a sticky write time that we should remove on close */ - bool sticky_write_time; - /* the open went through to completion */ bool open_completed; }; -- cgit From a0c6043c34abe5451e5de55791fc274e113504af Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 7 May 2008 16:50:19 +0200 Subject: libreplace: split out network checks into a AC_LIBREPLACE_NETWORK_CHECKS macro Note: moving it out of AC_LIBREPLACE_BROKEN_CHECKS will be the next step metze (This used to be commit 55a904b1d7aeca849d450e371b18afca5b0c6218) --- source4/lib/replace/libreplace.m4 | 65 +--------------------------- source4/lib/replace/libreplace_network.m4 | 71 +++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 63 deletions(-) create mode 100644 source4/lib/replace/libreplace_network.m4 diff --git a/source4/lib/replace/libreplace.m4 b/source4/lib/replace/libreplace.m4 index 8e17258918..1eba93792b 100644 --- a/source4/lib/replace/libreplace.m4 +++ b/source4/lib/replace/libreplace.m4 @@ -96,65 +96,10 @@ fi AC_CHECK_HEADERS(sys/syslog.h syslog.h) AC_CHECK_HEADERS(sys/time.h time.h) AC_CHECK_HEADERS(stdarg.h vararg.h) -AC_CHECK_HEADERS(sys/socket.h netinet/in.h netdb.h arpa/inet.h) -AC_CHECK_HEADERS(netinet/ip.h netinet/tcp.h netinet/in_systm.h netinet/in_ip.h) AC_CHECK_HEADERS(sys/sockio.h sys/un.h) AC_CHECK_HEADERS(sys/mount.h mntent.h) AC_CHECK_HEADERS(stropts.h) -dnl we need to check that net/if.h really can be used, to cope with hpux -dnl where including it always fails -AC_CACHE_CHECK([for usable net/if.h],libreplace_cv_USABLE_NET_IF_H,[ - AC_COMPILE_IFELSE([AC_LANG_SOURCE([ - AC_INCLUDES_DEFAULT - #if HAVE_SYS_SOCKET_H - # include - #endif - #include - int main(void) {return 0;}])], - [libreplace_cv_USABLE_NET_IF_H=yes], - [libreplace_cv_USABLE_NET_IF_H=no] - ) -]) -if test x"$libreplace_cv_USABLE_NET_IF_H" = x"yes";then - AC_DEFINE(HAVE_NET_IF_H, 1, usability of net/if.h) -fi - -AC_HAVE_TYPE([socklen_t],[#include ]) -AC_HAVE_TYPE([sa_family_t],[#include ]) -AC_HAVE_TYPE([struct addrinfo], [#include ]) -AC_HAVE_TYPE([struct sockaddr], [#include ]) -AC_HAVE_TYPE([struct sockaddr_storage], [ -#include -#include -#include -]) -AC_HAVE_TYPE([struct sockaddr_in6], [ -#include -#include -#include -]) - -if test x"$ac_cv_type_struct_sockaddr_storage" = x"yes"; then -AC_CHECK_MEMBER(struct sockaddr_storage.ss_family, - AC_DEFINE(HAVE_SS_FAMILY, 1, [Defined if struct sockaddr_storage has ss_family field]),, - [ -#include -#include -#include - ]) - -if test x"$ac_cv_member_struct_sockaddr_storage_ss_family" != x"yes"; then -AC_CHECK_MEMBER(struct sockaddr_storage.__ss_family, - AC_DEFINE(HAVE___SS_FAMILY, 1, [Defined if struct sockaddr_storage has __ss_family field]),, - [ -#include -#include -#include - ]) -fi -fi - AC_CHECK_FUNCS(seteuid setresuid setegid setresgid chroot bzero strerror) AC_CHECK_FUNCS(vsyslog setlinebuf mktime ftruncate chsize rename) AC_CHECK_FUNCS(waitpid strlcpy strlcat initgroups memmove strdup) @@ -326,19 +271,12 @@ m4_include(getpass.m4) m4_include(strptime.m4) m4_include(win32.m4) m4_include(timegm.m4) -m4_include(socket.m4) -m4_include(inet_ntop.m4) -m4_include(inet_pton.m4) -m4_include(inet_aton.m4) -m4_include(inet_ntoa.m4) -m4_include(getaddrinfo.m4) m4_include(repdir.m4) -m4_include(getifaddrs.m4) -m4_include(socketpair.m4) AC_CHECK_FUNCS([syslog printf memset memcpy],,[AC_MSG_ERROR([Required function not found])]) echo "LIBREPLACE_BROKEN_CHECKS: END" +AC_LIBREPLACE_NETWORK_CHECKS ]) dnl end AC_LIBREPLACE_BROKEN_CHECKS AC_DEFUN_ONCE(AC__LIBREPLACE_ALL_CHECKS_START, @@ -361,5 +299,6 @@ CFLAGS="$CFLAGS -I$libreplacedir" m4_include(libreplace_cc.m4) m4_include(libreplace_ld.m4) +m4_include(libreplace_network.m4) m4_include(libreplace_macros.m4) m4_include(autoconf-2.60.m4) diff --git a/source4/lib/replace/libreplace_network.m4 b/source4/lib/replace/libreplace_network.m4 new file mode 100644 index 0000000000..7702702799 --- /dev/null +++ b/source4/lib/replace/libreplace_network.m4 @@ -0,0 +1,71 @@ +AC_DEFUN_ONCE(AC_LIBREPLACE_NETWORK_CHECKS, +[ +echo "LIBREPLACE_NETWORK_CHECKS: START" + +AC_CHECK_HEADERS(sys/socket.h netinet/in.h netdb.h arpa/inet.h) +AC_CHECK_HEADERS(netinet/ip.h netinet/tcp.h netinet/in_systm.h netinet/in_ip.h) + +dnl we need to check that net/if.h really can be used, to cope with hpux +dnl where including it always fails +AC_CACHE_CHECK([for usable net/if.h],libreplace_cv_USABLE_NET_IF_H,[ + AC_COMPILE_IFELSE([AC_LANG_SOURCE([ + AC_INCLUDES_DEFAULT + #if HAVE_SYS_SOCKET_H + # include + #endif + #include + int main(void) {return 0;}])], + [libreplace_cv_USABLE_NET_IF_H=yes], + [libreplace_cv_USABLE_NET_IF_H=no] + ) +]) +if test x"$libreplace_cv_USABLE_NET_IF_H" = x"yes";then + AC_DEFINE(HAVE_NET_IF_H, 1, usability of net/if.h) +fi + +AC_HAVE_TYPE([socklen_t],[#include ]) +AC_HAVE_TYPE([sa_family_t],[#include ]) +AC_HAVE_TYPE([struct addrinfo], [#include ]) +AC_HAVE_TYPE([struct sockaddr], [#include ]) +AC_HAVE_TYPE([struct sockaddr_storage], [ +#include +#include +#include +]) +AC_HAVE_TYPE([struct sockaddr_in6], [ +#include +#include +#include +]) + +if test x"$ac_cv_type_struct_sockaddr_storage" = x"yes"; then +AC_CHECK_MEMBER(struct sockaddr_storage.ss_family, + AC_DEFINE(HAVE_SS_FAMILY, 1, [Defined if struct sockaddr_storage has ss_family field]),, + [ +#include +#include +#include + ]) + +if test x"$ac_cv_member_struct_sockaddr_storage_ss_family" != x"yes"; then +AC_CHECK_MEMBER(struct sockaddr_storage.__ss_family, + AC_DEFINE(HAVE___SS_FAMILY, 1, [Defined if struct sockaddr_storage has __ss_family field]),, + [ +#include +#include +#include + ]) +fi +fi + +m4_include(socket.m4) +m4_include(inet_ntop.m4) +m4_include(inet_pton.m4) +m4_include(inet_aton.m4) +m4_include(inet_ntoa.m4) +m4_include(getaddrinfo.m4) +m4_include(getifaddrs.m4) +m4_include(socketpair.m4) + +echo "LIBREPLACE_NETWORK_CHECKS: END" +]) dnl end AC_LIBREPLACE_NETWORK_CHECKS -- cgit From 63da424e8124a9def5d46f769804be661b059aab Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 7 May 2008 17:15:36 +0200 Subject: libreplace: use AC_LIBREPLACE_NETWORK_CHECKS only for samba metze (This used to be commit 3451b54bf7f5e37a589ec261d28c2a8b6f9788ed) --- source4/lib/replace/libreplace.m4 | 1 - source4/lib/replace/samba.m4 | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/lib/replace/libreplace.m4 b/source4/lib/replace/libreplace.m4 index 1eba93792b..2b33d97989 100644 --- a/source4/lib/replace/libreplace.m4 +++ b/source4/lib/replace/libreplace.m4 @@ -276,7 +276,6 @@ m4_include(repdir.m4) AC_CHECK_FUNCS([syslog printf memset memcpy],,[AC_MSG_ERROR([Required function not found])]) echo "LIBREPLACE_BROKEN_CHECKS: END" -AC_LIBREPLACE_NETWORK_CHECKS ]) dnl end AC_LIBREPLACE_BROKEN_CHECKS AC_DEFUN_ONCE(AC__LIBREPLACE_ALL_CHECKS_START, diff --git a/source4/lib/replace/samba.m4 b/source4/lib/replace/samba.m4 index 7984ef31db..07c4d38887 100644 --- a/source4/lib/replace/samba.m4 +++ b/source4/lib/replace/samba.m4 @@ -1,4 +1,5 @@ AC_LIBREPLACE_BROKEN_CHECKS +AC_LIBREPLACE_NETWORK_CHECKS SMB_EXT_LIB(LIBREPLACE_EXT, [${LIBDL}]) SMB_ENABLE(LIBREPLACE_EXT) -- cgit From 10a208fc4f8de6fdd20e5906f9fc6915124f6f83 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 7 May 2008 17:38:41 +0200 Subject: libreplace: also use AC_LIBREPLACE_NETWORK_CHECKS for the standalone build metze (This used to be commit 04f4523ed032946b8f0e74ac6f7458010159e3bb) --- source4/lib/replace/configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/source4/lib/replace/configure.ac b/source4/lib/replace/configure.ac index 02dc08bf72..81997e09b7 100644 --- a/source4/lib/replace/configure.ac +++ b/source4/lib/replace/configure.ac @@ -6,6 +6,7 @@ AC_CONFIG_HEADER(config.h) CFLAGS="$CFLAGS -I$srcdir" AC_LIBREPLACE_ALL_CHECKS +AC_LIBREPLACE_NETWORK_CHECKS if test "$ac_cv_prog_gcc" = yes; then CFLAGS="$CFLAGS -Wall" -- cgit From c3efee27b6190a7ceb7c0dbe4c526c0f51ddf871 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 8 May 2008 10:53:03 +0200 Subject: Install session.h, required by OpenChange's proxy. (This used to be commit 44d8b70004247729862b194ea66444e0cf296660) --- source4/auth/config.mk | 2 +- source4/headermap.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/source4/auth/config.mk b/source4/auth/config.mk index 87b796288d..b13b8abf1f 100644 --- a/source4/auth/config.mk +++ b/source4/auth/config.mk @@ -9,7 +9,7 @@ mkinclude credentials/config.mk PRIVATE_PROTO_HEADER = session_proto.h PUBLIC_DEPENDENCIES = CREDENTIALS -# PUBLIC_HEADERS += auth/session.h +PUBLIC_HEADERS += auth/session.h auth_session_OBJ_FILES = $(addprefix auth/, session.o) diff --git a/source4/headermap.txt b/source4/headermap.txt index bbd0d3c866..91e28b2a1a 100644 --- a/source4/headermap.txt +++ b/source4/headermap.txt @@ -71,3 +71,4 @@ lib/events/events_internal.h: events/events_internal.h libcli/ldap/ldap_ndr.h: ldap_ndr.h lib/events/events.h: events.h lib/events/events_internal.h: events_internal.h +auth/session.h: samba/session.h -- cgit From 4aba4d38c7cc1df4520df7f052d7d3c039597ed2 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 8 May 2008 11:56:32 +0200 Subject: Fix link flags for ldb and tdb Python modules. (This used to be commit 787a32fdef9d761d64839f489cca0b0684f9a9fd) --- source4/lib/ldb/ldb.mk | 2 +- source4/lib/tdb/tdb.mk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source4/lib/ldb/ldb.mk b/source4/lib/ldb/ldb.mk index cc920178bc..58ce598d06 100644 --- a/source4/lib/ldb/ldb.mk +++ b/source4/lib/ldb/ldb.mk @@ -71,7 +71,7 @@ ldb_wrap.o: $(ldbdir)/ldb_wrap.c $(CC) $(PICFLAG) -c $(ldbdir)/ldb_wrap.c $(CFLAGS) `$(PYTHON_CONFIG) --cflags` _ldb.$(SHLIBEXT): $(LIBS) ldb_wrap.o - $(SHLD) $(SHLD_FLAGS) -o _ldb.$(SHLIBEXT) ldb_wrap.o $(LIB_FLAGS) + $(SHLD) $(SHLD_FLAGS) -o _ldb.$(SHLIBEXT) ldb_wrap.o $(LIB_FLAGS) `$(PYTHON_CONFIG) --ldflagsb` install-python:: build-python mkdir -p $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(0, prefix='$(prefix)')"` \ diff --git a/source4/lib/tdb/tdb.mk b/source4/lib/tdb/tdb.mk index 0e53927366..c91b1289cb 100644 --- a/source4/lib/tdb/tdb.mk +++ b/source4/lib/tdb/tdb.mk @@ -39,7 +39,7 @@ tdb_wrap.o: $(tdbdir)/tdb_wrap.c $(CC) $(PICFLAG) -c $(tdbdir)/tdb_wrap.c $(CFLAGS) `$(PYTHON_CONFIG) --cflags` _tdb.$(SHLIBEXT): libtdb.$(SHLIBEXT) tdb_wrap.o - $(SHLD) $(SHLD_FLAGS) -o $@ tdb_wrap.o -L. -ltdb `$(PYTHON_CONFIG) --libs` + $(SHLD) $(SHLD_FLAGS) -o $@ tdb_wrap.o -L. -ltdb `$(PYTHON_CONFIG) --ldflags` install:: installdirs installbin installheaders installlibs \ $(PYTHON_INSTALL_TARGET) -- cgit From c68589a5dcefc2cd337449d343019271192fc11a Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 8 May 2008 12:40:56 +0200 Subject: Fix typo. (This used to be commit 1def988ef28de85b3f97172bdbf935a4fec4dec3) --- source4/lib/ldb/ldb.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/lib/ldb/ldb.mk b/source4/lib/ldb/ldb.mk index 58ce598d06..df11e9d2ab 100644 --- a/source4/lib/ldb/ldb.mk +++ b/source4/lib/ldb/ldb.mk @@ -71,7 +71,7 @@ ldb_wrap.o: $(ldbdir)/ldb_wrap.c $(CC) $(PICFLAG) -c $(ldbdir)/ldb_wrap.c $(CFLAGS) `$(PYTHON_CONFIG) --cflags` _ldb.$(SHLIBEXT): $(LIBS) ldb_wrap.o - $(SHLD) $(SHLD_FLAGS) -o _ldb.$(SHLIBEXT) ldb_wrap.o $(LIB_FLAGS) `$(PYTHON_CONFIG) --ldflagsb` + $(SHLD) $(SHLD_FLAGS) -o _ldb.$(SHLIBEXT) ldb_wrap.o $(LIB_FLAGS) `$(PYTHON_CONFIG) --ldflags` install-python:: build-python mkdir -p $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(0, prefix='$(prefix)')"` \ -- cgit From b3e1d69dcd58a72851b2efefd83ade377c9d2e85 Mon Sep 17 00:00:00 2001 From: William Jojo Date: Thu, 8 May 2008 12:41:57 +0200 Subject: Add undefined symbol flag for AIX. (This used to be commit dabdf24e86f038e3afc67532fa5bf60a37992161) --- source4/lib/replace/libreplace_ld.m4 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source4/lib/replace/libreplace_ld.m4 b/source4/lib/replace/libreplace_ld.m4 index f0d10c1e3e..0d0356055c 100644 --- a/source4/lib/replace/libreplace_ld.m4 +++ b/source4/lib/replace/libreplace_ld.m4 @@ -270,6 +270,10 @@ AC_DEFUN([AC_LIBREPLACE_LD_SHLIB_ALLOW_UNDEF_FLAG], *darwin*) LD_SHLIB_ALLOW_UNDEF_FLAG="-undefined dynamic_lookup" ;; + *aix*) + LD_SHLIB_ALLOW_UNDEF_FLAG="--Wl,-bnoentry" + ;; + ; esac AC_SUBST(LD_SHLIB_ALLOW_UNDEF_FLAG) -- cgit From ca6ac11b46a75bf02cf873c6aedb4f85af227168 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Thu, 8 May 2008 13:43:45 +0200 Subject: Fix typo. (This used to be commit bd089818a3182698dfe85039c1b2e22d8c2835bb) --- source4/lib/replace/libreplace_ld.m4 | 1 - 1 file changed, 1 deletion(-) diff --git a/source4/lib/replace/libreplace_ld.m4 b/source4/lib/replace/libreplace_ld.m4 index 0d0356055c..9995d69bbc 100644 --- a/source4/lib/replace/libreplace_ld.m4 +++ b/source4/lib/replace/libreplace_ld.m4 @@ -273,7 +273,6 @@ AC_DEFUN([AC_LIBREPLACE_LD_SHLIB_ALLOW_UNDEF_FLAG], *aix*) LD_SHLIB_ALLOW_UNDEF_FLAG="--Wl,-bnoentry" ;; - ; esac AC_SUBST(LD_SHLIB_ALLOW_UNDEF_FLAG) -- cgit From d0096e90ba9d8aa6b339022bac194e57ae0a2b7a Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 10 May 2008 00:46:25 +0200 Subject: Fix installation of pidl perl files, torture pc file. (This used to be commit 32da606e3759026c2744f853cd8948333ed0579c) --- source4/lib/torture/config.mk | 3 +++ source4/lib/torture/torture.pc.in | 12 ++++++++++++ source4/librpc/config.mk | 2 +- source4/pidl/config.mk | 2 +- source4/torture/torture.pc.in | 12 ------------ 5 files changed, 17 insertions(+), 14 deletions(-) create mode 100644 source4/lib/torture/torture.pc.in delete mode 100644 source4/torture/torture.pc.in diff --git a/source4/lib/torture/config.mk b/source4/lib/torture/config.mk index e981ee0c99..15c64786c5 100644 --- a/source4/lib/torture/config.mk +++ b/source4/lib/torture/config.mk @@ -5,6 +5,9 @@ PUBLIC_DEPENDENCIES = \ LIBSAMBA-UTIL \ LIBTALLOC +TORTURE_VERSION = 0.0.1 +TORTURE_SO_VERSION = 0 + PC_FILES += lib/torture/torture.pc torture_OBJ_FILES = $(addprefix lib/torture/, torture.o) diff --git a/source4/lib/torture/torture.pc.in b/source4/lib/torture/torture.pc.in new file mode 100644 index 0000000000..6582816cb5 --- /dev/null +++ b/source4/lib/torture/torture.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +modulesdir=${prefix}/modules/torture + +Name: torture +Description: Samba torture (test) suite +Requires: talloc +Version: 0.0.1 +Libs: -L${libdir} -ltorture +Cflags: -I${includedir} -DHAVE_IMMEDIATE_STRUCTURES=1 diff --git a/source4/librpc/config.mk b/source4/librpc/config.mk index 11a320a583..527fec92f6 100644 --- a/source4/librpc/config.mk +++ b/source4/librpc/config.mk @@ -340,7 +340,7 @@ NDR_WINSREPL_OBJ_FILES = librpc/gen_ndr/ndr_winsrepl.o PUBLIC_DEPENDENCIES = LIBNDR NDR_NETLOGON NDR_WINBIND_OBJ_FILES = librpc/gen_ndr/ndr_winbind.o -PUBLIC_HEADERS += librpc/gen_ndr/winbind.h +#PUBLIC_HEADERS += librpc/gen_ndr/winbind.h librpc/idl-deps: ./librpc/idl-deps.pl librpc/idl/*.idl >$@ diff --git a/source4/pidl/config.mk b/source4/pidl/config.mk index 25cea495a7..19b2d53659 100644 --- a/source4/pidl/config.mk +++ b/source4/pidl/config.mk @@ -6,7 +6,7 @@ pidl-testcov: pidl/Makefile installpidl:: pidl/Makefile $(MAKE) -C pidl install_vendor VENDORPREFIX=$(prefix) \ - INSTALLVENDORLIB=$(libdir) \ + INSTALLVENDORLIB=$(datarootdir)/perl5 \ INSTALLVENDORBIN=$(bindir) \ INSTALLVENDORSCRIPT=$(bindir) \ INSTALLVENDORMAN1DIR=$(mandir)/man1 \ diff --git a/source4/torture/torture.pc.in b/source4/torture/torture.pc.in deleted file mode 100644 index 6582816cb5..0000000000 --- a/source4/torture/torture.pc.in +++ /dev/null @@ -1,12 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ -modulesdir=${prefix}/modules/torture - -Name: torture -Description: Samba torture (test) suite -Requires: talloc -Version: 0.0.1 -Libs: -L${libdir} -ltorture -Cflags: -I${includedir} -DHAVE_IMMEDIATE_STRUCTURES=1 -- cgit From acb037fb1beaa0227c6b4e386d7a06b8191ec565 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 10 May 2008 00:48:11 +0200 Subject: Fix location of torture pc file. (This used to be commit 3e2c067ec734d8c14006ce9bec75a8ffccbf72c1) --- source4/configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/configure.ac b/source4/configure.ac index 66fb69694e..a845082fbf 100644 --- a/source4/configure.ac +++ b/source4/configure.ac @@ -31,7 +31,7 @@ m4_include(pidl/config.m4) AC_CONFIG_FILES(lib/registry/registry.pc) AC_CONFIG_FILES(librpc/dcerpc.pc) AC_CONFIG_FILES(librpc/ndr.pc) -AC_CONFIG_FILES(torture/torture.pc) +AC_CONFIG_FILES(lib/torture/torture.pc) AC_CONFIG_FILES(auth/gensec/gensec.pc) AC_CONFIG_FILES(param/samba-hostconfig.pc) AC_CONFIG_FILES(librpc/dcerpc_samr.pc) -- cgit From bc4eacb5d89ca8dca123e2d6bd6eba47ed93b771 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 10 May 2008 14:26:08 +0200 Subject: Fix case. (This used to be commit a90971ea0c43ce3b42b95aef5973139576b51959) --- source4/lib/torture/config.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source4/lib/torture/config.mk b/source4/lib/torture/config.mk index 15c64786c5..638f0d940c 100644 --- a/source4/lib/torture/config.mk +++ b/source4/lib/torture/config.mk @@ -5,8 +5,8 @@ PUBLIC_DEPENDENCIES = \ LIBSAMBA-UTIL \ LIBTALLOC -TORTURE_VERSION = 0.0.1 -TORTURE_SO_VERSION = 0 +torture_VERSION = 0.0.1 +torture_SO_VERSION = 0 PC_FILES += lib/torture/torture.pc torture_OBJ_FILES = $(addprefix lib/torture/, torture.o) -- cgit