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 e2079c2..54f1096 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 02de77e..9264cbb 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 69f0f63..2a1e44b 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 76c63a6..9606a60 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 28ca845..991f9d3 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 44487cd..c7d692a 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;