1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-23 17:34:34 +03:00

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 <garming@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
This commit is contained in:
Garming Sam 2016-04-01 10:10:57 +13:00 committed by Garming Sam
parent 5a0d1b7cc5
commit 878fa6ef7d
7 changed files with 114 additions and 22 deletions

View File

@ -5,12 +5,16 @@
<description> <description>
<para>The name of a program that can be used to check password <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> 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 <para>The program must return 0 on a good password, or any other value
if the password is bad. if the password is bad.
In case the password is considered weak (the program does not return 0) the 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> 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> <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> that uses cracklib to check the password quality.</para>

View File

@ -27,20 +27,8 @@
#include "includes.h" #include "includes.h"
#include "system/filesys.h" #include "system/filesys.h"
#include <tevent.h>
#include "../lib/util/tevent_unix.h" #include "../lib/util/tevent_unix.h"
#include "../lib/util/util_runcmd.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;
};
static int samba_runcmd_state_destructor(struct samba_runcmd_state *state) static int samba_runcmd_state_destructor(struct samba_runcmd_state *state)
{ {

35
lib/util/util_runcmd.h Normal file
View File

@ -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;
};

View File

@ -44,6 +44,7 @@
#include "lib/socket/socket.h" #include "lib/socket/socket.h"
#include "librpc/gen_ndr/irpc.h" #include "librpc/gen_ndr/irpc.h"
#include "libds/common/flag_mapping.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 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") * 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 pwdProperties,
const uint32_t minPwdLength) const uint32_t minPwdLength)
{ {
const char *utf8_pw = (const char *)utf8_blob->data; const char *utf8_pw = (const char *)utf8_blob->data;
size_t utf8_len = strlen_m(utf8_pw); size_t utf8_len = strlen_m(utf8_pw);
char *password_script = NULL;
/* checks if the "minPwdLength" property is satisfied */ /* checks if the "minPwdLength" property is satisfied */
if (minPwdLength > utf8_len) { 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; 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)) { if (!check_password_quality(utf8_pw)) {
return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH; return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
} }

View File

@ -2106,10 +2106,11 @@ done:
static int check_password_restrictions(struct setup_password_fields_io *io) 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; int ret;
struct loadparm_context *lp_ctx =
ldb = ldb_module_get_ctx(io->ac->module); lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
struct loadparm_context);
if (!io->ac->update_password) { if (!io->ac->update_password) {
return LDB_SUCCESS; return LDB_SUCCESS;
@ -2175,7 +2176,8 @@ static int check_password_restrictions(struct setup_password_fields_io *io)
*/ */
if (io->n.cleartext_utf8 != NULL) { if (io->n.cleartext_utf8 != NULL) {
enum samr_ValidationStatus vstat; 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.pwdProperties,
io->ac->status->domain_data.minPwdLength); io->ac->status->domain_data.minPwdLength);
switch (vstat) { switch (vstat) {

View File

@ -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', 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', autoproto='common/proto.h',
private_library=True, 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'
) )

View File

@ -4400,7 +4400,9 @@ static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call,
case NetValidatePasswordChange: case NetValidatePasswordChange:
password = data_blob_const(r->in.req->req2.password.string, password = data_blob_const(r->in.req->req2.password.string,
r->in.req->req2.password.length); 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.password_properties,
pwInfo.min_password_length); pwInfo.min_password_length);
(*r->out.rep)->ctr2.status = res; (*r->out.rep)->ctr2.status = res;
@ -4408,7 +4410,9 @@ static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call,
case NetValidatePasswordReset: case NetValidatePasswordReset:
password = data_blob_const(r->in.req->req3.password.string, password = data_blob_const(r->in.req->req3.password.string,
r->in.req->req3.password.length); 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.password_properties,
pwInfo.min_password_length); pwInfo.min_password_length);
(*r->out.rep)->ctr3.status = res; (*r->out.rep)->ctr3.status = res;