From 878fa6ef7de420ed7f28e95113bb76bf50879553 Mon Sep 17 00:00:00 2001 From: Garming Sam Date: Fri, 1 Apr 2016 10:10:57 +1300 Subject: [PATCH] check-password-script: Allow AD to execute these scripts In contrast to source3, this is run as root and without substitution. Signed-off-by: Garming Sam Reviewed-by: Andrew Bartlett --- .../security/checkpasswordscript.xml | 6 +- lib/util/util_runcmd.c | 14 +---- lib/util/util_runcmd.h | 35 +++++++++++ source4/dsdb/common/util.c | 61 ++++++++++++++++++- .../dsdb/samdb/ldb_modules/password_hash.c | 10 +-- source4/dsdb/wscript_build | 2 +- source4/rpc_server/samr/dcesrv_samr.c | 8 ++- 7 files changed, 114 insertions(+), 22 deletions(-) create mode 100644 lib/util/util_runcmd.h diff --git a/docs-xml/smbdotconf/security/checkpasswordscript.xml b/docs-xml/smbdotconf/security/checkpasswordscript.xml index e2079c2515a..54f1096802b 100644 --- a/docs-xml/smbdotconf/security/checkpasswordscript.xml +++ b/docs-xml/smbdotconf/security/checkpasswordscript.xml @@ -5,12 +5,16 @@ The name of a program that can be used to check password complexity. The password is sent to the program's standard input. - + The program must return 0 on a good password, or any other value if the password is bad. In case the password is considered weak (the program does not return 0) the user will be notified and the password change will fail. + In Samba AD, this script will be run AS ROOT by + samba 8 + without any substitutions. + Note: In the example directory is a sample program called crackcheck that uses cracklib to check the password quality. diff --git a/lib/util/util_runcmd.c b/lib/util/util_runcmd.c index 02de77ee864..9264cbba11b 100644 --- a/lib/util/util_runcmd.c +++ b/lib/util/util_runcmd.c @@ -27,20 +27,8 @@ #include "includes.h" #include "system/filesys.h" -#include #include "../lib/util/tevent_unix.h" - -struct samba_runcmd_state { - int stdout_log_level; - int stderr_log_level; - struct tevent_fd *fde_stdout; - struct tevent_fd *fde_stderr; - int fd_stdin, fd_stdout, fd_stderr; - char *arg0; - pid_t pid; - char buf[1024]; - uint16_t buf_used; -}; +#include "../lib/util/util_runcmd.h" static int samba_runcmd_state_destructor(struct samba_runcmd_state *state) { diff --git a/lib/util/util_runcmd.h b/lib/util/util_runcmd.h new file mode 100644 index 00000000000..26fdbc66042 --- /dev/null +++ b/lib/util/util_runcmd.h @@ -0,0 +1,35 @@ +/* + Unix SMB/CIFS implementation. + + run a child command + + Copyright (C) Andrew Tridgell 2010 + + 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 + +struct samba_runcmd_state { + int stdout_log_level; + int stderr_log_level; + struct tevent_fd *fde_stdout; + struct tevent_fd *fde_stderr; + int fd_stdin, fd_stdout, fd_stderr; + char *arg0; + pid_t pid; + char buf[1024]; + uint16_t buf_used; +}; diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 69f0f631de8..2a1e44b5263 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -44,6 +44,7 @@ #include "lib/socket/socket.h" #include "librpc/gen_ndr/irpc.h" #include "libds/common/flag_mapping.h" +#include "../lib/util/util_runcmd.h" /* search the sam for the specified attributes in a specific domain, filter on @@ -1988,12 +1989,15 @@ int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, * * Result codes from "enum samr_ValidationStatus" (consider "samr.idl") */ -enum samr_ValidationStatus samdb_check_password(const DATA_BLOB *utf8_blob, +enum samr_ValidationStatus samdb_check_password(TALLOC_CTX *mem_ctx, + struct loadparm_context *lp_ctx, + const DATA_BLOB *utf8_blob, const uint32_t pwdProperties, const uint32_t minPwdLength) { const char *utf8_pw = (const char *)utf8_blob->data; size_t utf8_len = strlen_m(utf8_pw); + char *password_script = NULL; /* checks if the "minPwdLength" property is satisfied */ if (minPwdLength > utf8_len) { @@ -2009,6 +2013,61 @@ enum samr_ValidationStatus samdb_check_password(const DATA_BLOB *utf8_blob, return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH; } + password_script = lpcfg_check_password_script(lp_ctx, mem_ctx); + if (password_script != NULL && *password_script != '\0') { + int check_ret = 0; + int error = 0; + struct tevent_context *event_ctx = NULL; + struct tevent_req *req = NULL; + struct samba_runcmd_state *run_cmd = NULL; + const char * const cmd[4] = { + "/bin/sh", "-c", + password_script, + NULL + }; + + event_ctx = tevent_context_init(mem_ctx); + if (event_ctx == NULL) { + TALLOC_FREE(password_script); + return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR; + } + + req = samba_runcmd_send(mem_ctx, event_ctx, + tevent_timeval_current_ofs(0, 10000000), + 100, 100, cmd, NULL); + run_cmd = tevent_req_data(req, struct samba_runcmd_state); + if (write(run_cmd->fd_stdin, utf8_pw, utf8_len) != utf8_len) { + TALLOC_FREE(password_script); + return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR; + } + + close(run_cmd->fd_stdin); + run_cmd->fd_stdin = -1; + + if (!tevent_req_poll(req, event_ctx)) { + TALLOC_FREE(password_script); + return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR; + } + + check_ret = samba_runcmd_recv(req, &error); + TALLOC_FREE(req); + + DEBUG(5,("check_password_complexity: check password script (%s) " + "returned [%d]\n", password_script, check_ret)); + TALLOC_FREE(password_script); + + if (check_ret != 0) { + DEBUG(1,("check_password_complexity: " + "check password script said new password is not good " + "enough!\n")); + return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH; + } + + return SAMR_VALIDATION_STATUS_SUCCESS; + } + + TALLOC_FREE(password_script); + if (!check_password_quality(utf8_pw)) { return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH; } diff --git a/source4/dsdb/samdb/ldb_modules/password_hash.c b/source4/dsdb/samdb/ldb_modules/password_hash.c index 76c63a655b9..9606a60a5d7 100644 --- a/source4/dsdb/samdb/ldb_modules/password_hash.c +++ b/source4/dsdb/samdb/ldb_modules/password_hash.c @@ -2106,10 +2106,11 @@ done: static int check_password_restrictions(struct setup_password_fields_io *io) { - struct ldb_context *ldb; + struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module); int ret; - - ldb = ldb_module_get_ctx(io->ac->module); + struct loadparm_context *lp_ctx = + lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"), + struct loadparm_context); if (!io->ac->update_password) { return LDB_SUCCESS; @@ -2175,7 +2176,8 @@ static int check_password_restrictions(struct setup_password_fields_io *io) */ if (io->n.cleartext_utf8 != NULL) { enum samr_ValidationStatus vstat; - vstat = samdb_check_password(io->n.cleartext_utf8, + vstat = samdb_check_password(io->ac, lp_ctx, + io->n.cleartext_utf8, io->ac->status->domain_data.pwdProperties, io->ac->status->domain_data.minPwdLength); switch (vstat) { diff --git a/source4/dsdb/wscript_build b/source4/dsdb/wscript_build index 28ca8450cf8..991f9d3478f 100755 --- a/source4/dsdb/wscript_build +++ b/source4/dsdb/wscript_build @@ -16,7 +16,7 @@ bld.SAMBA_LIBRARY('samdb-common', source='common/util.c common/util_trusts.c common/util_groups.c common/util_samr.c common/dsdb_dn.c common/dsdb_access.c', autoproto='common/proto.h', private_library=True, - deps='ldb NDR_DRSBLOBS util_ldb LIBCLI_AUTH samba-hostconfig samba_socket cli-ldap-common flag_mapping' + deps='ldb NDR_DRSBLOBS util_ldb LIBCLI_AUTH samba-hostconfig samba_socket cli-ldap-common flag_mapping UTIL_RUNCMD' ) diff --git a/source4/rpc_server/samr/dcesrv_samr.c b/source4/rpc_server/samr/dcesrv_samr.c index 44487cd7db6..c7d692a1b56 100644 --- a/source4/rpc_server/samr/dcesrv_samr.c +++ b/source4/rpc_server/samr/dcesrv_samr.c @@ -4400,7 +4400,9 @@ static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call, case NetValidatePasswordChange: password = data_blob_const(r->in.req->req2.password.string, r->in.req->req2.password.length); - res = samdb_check_password(&password, + res = samdb_check_password(mem_ctx, + dce_call->conn->dce_ctx->lp_ctx, + &password, pwInfo.password_properties, pwInfo.min_password_length); (*r->out.rep)->ctr2.status = res; @@ -4408,7 +4410,9 @@ static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call, case NetValidatePasswordReset: password = data_blob_const(r->in.req->req3.password.string, r->in.req->req3.password.length); - res = samdb_check_password(&password, + res = samdb_check_password(mem_ctx, + dce_call->conn->dce_ctx->lp_ctx, + &password, pwInfo.password_properties, pwInfo.min_password_length); (*r->out.rep)->ctr3.status = res; -- 2.34.1