check-password-script: Allow AD to execute these scripts
authorGarming Sam <garming@catalyst.net.nz>
Thu, 31 Mar 2016 21:10:57 +0000 (10:10 +1300)
committerGarming Sam <garming@samba.org>
Mon, 4 Jul 2016 22:00:14 +0000 (00:00 +0200)
In contrast to source3, this is run as root and without substitution.

Signed-off-by: Garming Sam <garming@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
docs-xml/smbdotconf/security/checkpasswordscript.xml
lib/util/util_runcmd.c
lib/util/util_runcmd.h [new file with mode: 0644]
source4/dsdb/common/util.c
source4/dsdb/samdb/ldb_modules/password_hash.c
source4/dsdb/wscript_build
source4/rpc_server/samr/dcesrv_samr.c

index e2079c2515a37210390087e816bc86f7cc2ea2d9..54f1096802b94598d4592b087695d85416e04ec7 100644 (file)
@@ -5,12 +5,16 @@
 <description>
     <para>The name of a program that can be used to check password
     complexity. The password is sent to the program's standard input.</para>
+
     <para>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.</para>
 
+    <para>In Samba AD, this script will be run <emphasis>AS ROOT</emphasis> by
+    <citerefentry><refentrytitle>samba</refentrytitle> <manvolnum>8</manvolnum>
+    </citerefentry> without any substitutions.</para>
+
     <para>Note: In the example directory is a sample program called <command moreinfo="none">crackcheck</command>
     that uses cracklib to check the password quality.</para>
 
index 02de77ee864d00e5ec8a0c2d6f48699e770bdd3a..9264cbba11b60c586f9a06be7f946aa4f55c0a9a 100644 (file)
 
 #include "includes.h"
 #include "system/filesys.h"
-#include <tevent.h>
 #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 (file)
index 0000000..26fdbc6
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <tevent.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;
+};
index 69f0f631de852cc8ecc5b67c51036a5c7011235b..2a1e44b526368ff78e2f3991d8324b3ab9eaf55e 100644 (file)
@@ -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;
        }
index 76c63a655b90367b8917c2bcdeb5adb213ad6e1a..9606a60a5d75a8fa7cf058d5b7a58c238e744366 100644 (file)
@@ -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) {
index 28ca8450cf842b79efefe6a88625eaeb2478ad53..991f9d3478ffcc472eb4113e345719506b34a741 100755 (executable)
@@ -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'
        )
 
 
index 44487cd7db66e06f3635941a0908da408b58b046..c7d692a1b56f32cf7b5d40ce98888322f66fd210 100644 (file)
@@ -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;