password-quality diff
Pierre Belanger
pbelang1 at oss.cantel.rogers.com
Mon May 5 17:29:10 GMT 2003
Hi,
Here's "password-quality.diff" to apply to HEAD. I'm also including
password-quality.smb.conf.5.sgml "diff".
NEW FILES: source/smbd/password-quality.c
examples/password-quality/password-quality.pl
MOD FILES: source/Makefile.in (added password-quality.o)
source/param/loadparm.c (added password quality script)
source/smbd/chgpasswd.c (mod. to call password quality)
Documentation: Sorry but I was not able to ind which file to modif.
for the creation of the "smb.conf.*" files. If someone tells me,
I can provide a diff later. I included a diff againts the old
smb.conf.5.sgml .
Fell free to apply any changes you think is necessary or remove
things you think is ! necessary.
I put some "Doxygen" stuff in there but I really don't know if this
is good or not. Fell free to remove/change it.
The Perl script "simple", I hope it's a "good start" example until
others contribute.
Sorry for the delai, just too much to do since the pass months
besides begin sick like hell for a while.
Best regards,
Pierre B.
-------------- next part --------------
--- examples/password-quality/password-quality.pl Mon May 5 11:04:41 2003
+++ ../samba-head-work/examples/password-quality/password-quality.pl Mon May 5 11:03:55 2003
@@ -0,0 +1,187 @@
+#!/usr/bin/perl -w
+#
+# Simple Password Quality for Samba
+#
+# Copyright (C) Pierre Belanger 2003 - belanger at pobox.com
+#
+###
+# 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 2 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, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###
+#
+# The first goal of this program is to show how Samba's "password quality
+# script" interface works. Fell free to apply your own modifications to
+# this scritp or to write your own program based on this example. Always
+# remember to be carefull -- this script is running under uid and gid root!
+#
+# This program does the following:
+#
+# Accept password change request -- if and only if:
+#
+# 1) Password has at least one UPPERcase character
+# 2) Password has at least one LOWERcase character
+# 3) Password has at least one Number character
+# 4) Password has at least one Special character
+# 5) Password has a minimum length of 7 characters
+# 6) Password has a maximum length of 8 characters
+#
+# All previous values are options that may be turned on or off.
+#
+###
+use strict;
+
+#
+# Configuration options
+#
+my $minLengthPassword = 7;
+my $maxLengthPassword = 8;
+my $mustHaveUppercase = 1; # [A-Z]
+my $mustHaveLowercase = 1; # [a-z]
+my $mustHaveNumber = 1; # [0-9]
+my $mustHaveSpecial = 1; # [~!@#$%^&*()_[ ]+=-`{}:;"'<>,./?\|]
+my $MY_PROTOCOL_VERSION = 1; #
+
+# Run as user
+my $runas_user = "nobody";
+
+#
+# End of configuration options
+#
+
+# init variables
+my $line = "";
+my $protoversion= "";
+my $username = "";
+my $fullname = "";
+my $password = "";
+my $lpassword = 0;
+my $message = "";
+
+# NTStatus exit status
+my $NT_STATUS_OK = 0;
+
+# Switch to user $runas_user
+my ($uid,$gid)=(getpwnam($runas_user))[2,3];
+if ($uid && $gid) {
+ $)="$gid $gid";
+ $(=$gid;
+ $<=$uid;
+ $>=$gid;
+ if (($< != $uid) || ($> != $gid)) {
+ printf "NTStatus: NT_STATUS_ACCESS_DENIED\n";
+ printf "Result: Can't switch to user $runas_user!\n";
+ printf ".\n";
+ exit($NT_STATUS_OK);
+ }
+} else {
+ printf "NTStatus: NT_STATUS_ACCESS_DENIED\n";
+ printf "Result: Can't switch to user $runas_user -- getpwnam() failed!\n";
+ printf ".\n";
+ exit($NT_STATUS_OK);
+}
+
+# Get data from smbd
+while ($line = <STDIN>) {
+
+ chomp($line);
+
+ if ("$line" eq ".") {
+ goto CHECKPASSWORD;
+ }
+ if ($line =~ s/^Username: //) {
+ $username = $line;
+ next;
+ }
+ if ($line =~ s/^Fullname: //) {
+ $fullname = $line;
+ next;
+ }
+ if ($line =~ s/^Password: //) {
+ $password = $line;
+ $lpassword = length $password;
+ next;
+ }
+ if ($line =~ s/^Version: //) {
+ $protoversion = $line;
+ next;
+ }
+}
+
+if (! defined $line) {
+ print "NTSTATUS: NT_STATUS_ACCESS_DENIED\n";
+ print "RESULT: FATAL ERROR - Received EOF prior to '.\\n'\n";
+ print ".\n";
+ exit($NT_STATUS_OK);
+}
+
+CHECKPASSWORD:
+
+if ($protoversion gt $MY_PROTOCOL_VERSION) {
+ print "NTSTATUS: NT_STATUS_ACCESS_DENIED\n";
+ print "RESULT: smbd protocol version $protoversion > $MY_PROTOCOL_VERSION\n";
+ print ".\n";
+ exit($NT_STATUS_OK);
+}
+
+if (length $username == 0) {
+ print "NTSTATUS: NT_STATUS_ACCESS_DENIED\n";
+ print "RESULT: FATAL ERROR - Did not receive username\n";
+ print ".\n";
+ exit($NT_STATUS_OK);
+}
+if ($lpassword == 0) {
+ print "NTSTATUS: NT_STATUS_ACCESS_DENIED\n";
+ print "RESULT: FATAL ERROR - Did not receive password\n";
+ print ".\n";
+ exit($NT_STATUS_OK);
+}
+
+if ("$username" eq "$password") {
+ print "NTSTATUS: NT_STATUS_ACCESS_DENIED\n";
+ print "RESULT: FATAL ERROR - Username == Password\n";
+ print ".\n";
+ exit ($NT_STATUS_OK);
+}
+if ($lpassword < $minLengthPassword) {
+ $message .= "Too short. ";
+}
+if ($lpassword > $maxLengthPassword) {
+ $message .= "Too long (" . $lpassword . "). ";
+}
+if (! ($password =~ /[A-Z]+/) && $mustHaveUppercase) {
+ $message .= "No uppercase. ";
+}
+if (! ($password =~ /[a-z]+/) && $mustHaveLowercase) {
+ $message .= "No lowercase. ";
+}
+if (! ($password =~ /[0-9]+/) && $mustHaveNumber) {
+ $message .= "No number. ";
+}
+if (! ($password =~ /[\ -\/]|[:-@]|[\[-`]|[{-~]/) && $mustHaveSpecial) {
+ $message .= "No special char. ";
+}
+
+if (length $message > 0) {
+ $message =~ s/\s*$//; # Strip trailing space.
+ print "NTSTATUS: NT_STATUS_PASSWORD_RESTRICTION\n";
+ print "RESULT: $message\n";
+ print ".\n";
+ exit($NT_STATUS_OK);
+} else {
+ print "NTSTATUS: NT_STATUS_OK\n";
+ print "RESULT: New password accepted.\n";
+ print ".\n";
+ exit($NT_STATUS_OK);
+}
--- source/Makefile.in Mon May 5 09:26:53 2003
+++ ../samba-head-work/source/Makefile.in Mon May 5 09:29:45 2003
@@ -331,7 +331,7 @@
SMBD_OBJ_MAIN = smbd/server.o
SMBD_OBJ_SRV = smbd/files.o smbd/chgpasswd.o smbd/connection.o \
- smbd/utmp.o smbd/session.o \
+ smbd/utmp.o smbd/session.o smbd/password-quality.o \
smbd/dfree.o smbd/dir.o smbd/password.o smbd/conn.o smbd/fileio.o \
smbd/ipc.o smbd/lanman.o smbd/negprot.o \
smbd/message.o smbd/nttrans.o smbd/pipes.o \
--- source/param/loadparm.c Mon May 5 09:27:06 2003
+++ ../samba-head-work/source/param/loadparm.c Mon May 5 09:29:52 2003
@@ -290,6 +290,7 @@
int name_cache_timeout;
BOOL client_signing;
param_opt_struct *param_opt;
+ char *szPasswordqualityscript;
}
global;
@@ -929,6 +930,7 @@
{"enumports command", P_STRING, P_GLOBAL, &Globals.szEnumPortsCommand, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
{"addprinter command", P_STRING, P_GLOBAL, &Globals.szAddPrinterCommand, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
+ {"password quality script", P_STRING, P_GLOBAL, &Globals.szPasswordqualityscript, NULL, NULL, FLAG_GLOBAL},
{"deleteprinter command", P_STRING, P_GLOBAL, &Globals.szDeletePrinterCommand, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
{"show add printer wizard", P_BOOL, P_GLOBAL, &Globals.bMsAddPrinterWizard, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
{"os2 driver map", P_STRING, P_GLOBAL, &Globals.szOs2DriverMap, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
@@ -1473,6 +1475,8 @@
Globals.bClientUseSpnego = True;
string_set(&Globals.smb_ports, SMB_PORTS);
+
+ string_set(&Globals.szPasswordqualityscript, "");
}
static TALLOC_CTX *lp_talloc;
@@ -1593,6 +1597,7 @@
FN_GLOBAL_STRING(lp_defaultservice, &Globals.szDefaultService)
FN_GLOBAL_STRING(lp_msg_command, &Globals.szMsgCommand)
FN_GLOBAL_STRING(lp_dfree_command, &Globals.szDfree)
+FN_GLOBAL_STRING(lp_password_quality_script, &Globals.szPasswordqualityscript)
FN_GLOBAL_STRING(lp_hosts_equiv, &Globals.szHostsEquiv)
FN_GLOBAL_STRING(lp_auto_services, &Globals.szAutoServices)
FN_GLOBAL_STRING(lp_passwd_program, &Globals.szPasswdProgram)
--- source/smbd/password-quality.c Mon May 5 13:11:20 2003
+++ ../samba-head-work/source/smbd/password-quality.c Mon May 5 13:01:04 2003
@@ -0,0 +1,458 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+
+ Password Quality: Help users not to choose a weak password.
+
+ Copyright (C) Andrew Bartlett 2003
+ Copyright (C) Pierre Belanger 2003 (belanger at pobox.com)
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* Increment when making changes in the communication protocol */
+#define PWQUAL_PROTOCOL_VERSION "1"
+
+static void gotalarm_sig(void);
+static char ascii2hex(char ascii);
+static int ZEROxStr2uint32(char *strx, uint32 *hex32);
+static NTSTATUS password_quality_script(SAM_ACCOUNT *hnd, char *new_passwd);
+static BOOL strhasctrl(const char *str);
+static NTSTATUS pre_chk(const char *username,const char *fullname,char *new_pw);
+
+static int gotalarm;
+
+
+/**@ingroup password-quality
+ * Signal (SIGALRM) function to tell us we timed out.
+ *
+*/
+static void gotalarm_sig(void)
+{
+ gotalarm = 1;
+}
+
+
+/**@ingroup password-quality
+ * Main function to catch weak new passwords
+ *
+ * @param hnd SAM_ACCOUNT requesting a password change
+ *
+ * @param new_password The user's new password
+ *
+ * @return NTSTATUS
+ *
+*/
+NTSTATUS password_quality(SAM_ACCOUNT *hnd, char *new_password)
+{
+ NTSTATUS ntstatusresult;
+
+ ntstatusresult = password_quality_script(hnd, new_password);
+
+ if (!NT_STATUS_IS_OK(ntstatusresult)) {
+ DEBUG(1,("user %s could not change password NTSTATUS=0x%0.8x\n",
+ pdb_get_username(hnd), ntstatusresult.v));
+ return ntstatusresult;
+ }
+
+ /* Add other supports here if needed */
+
+ DEBUG(0,("user %s changed password\n", pdb_get_username(hnd)));
+ return(ntstatusresult);
+}
+
+
+/**@ingroup password-quality
+ * Function to run the password quality script.
+ *
+ * @param hnd SAM_ACCOUNT requesting a password change
+ *
+ * @param new_password The user's new password
+ *
+ * @return NTSTATUS
+ *
+*/
+static NTSTATUS password_quality_script(SAM_ACCOUNT *hnd, char *new_passwd)
+{
+ int fd1[2], fd2[2];
+ char *cmdname;
+ const char *username, *fullname;
+ pid_t child_pid;
+ NTSTATUS ntprerun;
+
+ /* check if command is configured */
+ cmdname = lp_password_quality_script();
+ if (!cmdname || (*cmdname == '\0'))
+ return NT_STATUS_OK;
+
+ username = pdb_get_username(hnd);
+ fullname = pdb_get_fullname(hnd);
+
+ /* pre-run security check */
+ ntprerun = pre_chk(username, fullname, new_passwd);
+ if (!NT_STATUS_IS_OK(ntprerun)) {
+ return ntprerun;
+ }
+
+ if (pipe(fd1) || pipe(fd2)) {
+ DEBUG(0,("could not create pipes\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ CatchChildLeaveStatus();
+ child_pid = sys_fork();
+
+ if (child_pid < 0) {
+ close(fd1[0]); close(fd1[1]);
+ close(fd2[0]); close(fd2[1]);
+ DEBUG(0,("could not fork -- out of resources\n"));
+ CatchChild();
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (child_pid > 0) {
+
+ /*
+ * Parent.
+ */
+
+ int fd_in, fd_out, done, child_status;
+ pid_t wpid;
+ ssize_t length;
+ char *c, *buf, *reservedword, *msg;
+ pstring pbuf, pntstatus, presult;
+ NTSTATUS ntstatusmap;
+ void (*oldsighandler)(int);
+
+ close(fd1[0]); close(fd2[1]);
+ fd_out = fd1[1]; fd_in = fd2[0];
+
+ asprintf (&buf, "Version: %s\nUsername: %s\nFullName: %s\n"
+ "Password: %s\n.\n", PWQUAL_PROTOCOL_VERSION,
+ username, fullname, new_passwd);
+
+ if ((length = sys_write(fd_out, buf, strlen(buf))) < 0 ) {
+ close(fd_out); close(fd_in);
+ SAFE_FREE(buf);
+ DEBUG(0,("sys_write returned %s\n", strerror(errno)));
+ kill(child_pid, SIGKILL);
+ sys_waitpid(child_pid, &child_status, 0);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ SAFE_FREE(buf);
+ DEBUG(5,("sys_write wrote %d characters\n", length));
+
+ /* don't hang in read() due to a broken program */
+ oldsighandler = CatchSignal(SIGALRM,SIGNAL_CAST gotalarm_sig);
+ alarm(15); /* cli->timeout set to 20000ms */
+ gotalarm = 0;
+
+ while((length = read(fd_in, &pbuf[0], PSTRING_LEN - 1)) < 0) {
+
+ if (gotalarm == 1) {
+ kill(child_pid, SIGTERM);
+ DEBUG(0,("read timeout waiting for child\n"));
+ break;
+ }
+ if ((length == -1) && (errno == EINTR)) {
+ errno = 0;
+ continue;
+ }
+
+ DEBUG(0,("read error %s\n", strerror(errno)));
+ break;
+
+ }
+ close(fd_out); close(fd_in);
+ if (length > 0)
+ DEBUG(5,("read returned %d characters\n", length));
+
+ /* get child exit status */
+ alarm(2); gotalarm = 0;
+ while((wpid = sys_waitpid(child_pid, &child_status, 0)) < 0) {
+
+ if (gotalarm == 1) {
+ DEBUG(0,("exit status timeout\n"));
+ kill(child_pid, SIGKILL);
+ gotalarm = 0; /* avoid loop */
+ continue;
+ }
+ if(errno == EINTR) {
+ errno = 0;
+ continue;
+ }
+
+ DEBUG(0,("could not get child exit status\n"));
+ break;
+ }
+ alarm(0);
+ CatchSignal(SIGALRM, SIGNAL_CAST oldsighandler);
+ CatchChild();
+ if (wpid == child_pid)
+ DEBUG(5,("child exit status %d\n", child_status));
+
+ if (length < 0 || wpid < 0)
+ return NT_STATUS_ACCESS_DENIED;
+
+ /* check child exit status */
+ if (!NT_STATUS_IS_OK(map_nt_error_from_unix(child_status))) {
+ DEBUG(0,("error: child exit(%d) != 0\n", child_status));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (length == 0) {
+ DEBUG(0,("child returned nothing - read length = 0\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* Parse response from external program */
+ pbuf[length] = '\0'; presult[0] = '\0';pntstatus[0] = '\0';
+ done = 0;
+ for (c = &pbuf[0]; *c != '\0'; c++) {
+
+ if (!strcmp(c, ".\n")) {
+ done = 1;
+ break;
+ }
+
+ reservedword = c;
+ if ((c = strpbrk(c, " :")) == (char *)NULL) {
+ DEBUG(1,("received bad response %s\n",
+ reservedword));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ *c = '\0'; /* end of reserved word */
+ c++;
+
+ while (((*c==' ')||(*c==':'))&&(*c!='\0'))
+ c++;
+ msg = c;
+
+ if ((c = strpbrk(c, "\n")) == (char *)NULL) {
+ DEBUG(1,("received bad response %s: %s!\n",
+ reservedword, msg));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ *c = '\0'; /* end of message */
+
+ if (!StrCaseCmp(reservedword, "ntstatus")) {
+ pstrcpy(pntstatus, msg);
+ DEBUG(3,("got %s: %s\n", reservedword, msg));
+ continue;
+ }
+ if (!StrCaseCmp(reservedword, "result")) {
+ pstrcpy(presult, msg);
+ DEBUG(3,("got %s: %s\n", reservedword, msg));
+ continue;
+ }
+ DEBUG(1,("unsupported %s: %s\n", reservedword, msg));
+ break; /* child is broken or not up to date, break */
+
+ } /* parse end */
+
+ if (!done || (pntstatus[0]=='\0') || (presult[0]=='\0')) {
+ DEBUG(0,("bad communication with child\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ DEBUG(1,("got NTStatus: %s Result: %s\n", pntstatus, presult));
+
+ if (!StrnCaseCmp(pntstatus, "0x", 2)) {
+ /*
+ * pntstatus is 0x... hexstring format
+ */
+ uint32 nthex;
+
+ if (ZEROxStr2uint32(pntstatus, &nthex)) {
+ DEBUG(1,("received bad hex '%s'\n", pntstatus));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ DEBUG(4,("ZEROxstr2uint32 returned 0x%0.8x\n", nthex));
+ ntstatusmap = NT_STATUS(nthex);
+
+ } else {
+ /*
+ * pntstatus should be a NTSTATUS string
+ */
+ ntstatusmap = nt_status_string_to_code(pntstatus);
+
+ if NT_STATUS_EQUAL(ntstatusmap,NT_STATUS_UNSUCCESSFUL) {
+ /* if there is no match, deny change */
+ DEBUG(1,("received undefined NTSTATUS %s\n",
+ pntstatus));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ }
+
+ /* return received hex value or a matched NTSTATUS string */
+ return ntstatusmap;
+
+ } else {
+
+ /*
+ * Child.
+ */
+
+ int fd_null;
+
+ CatchChild();
+
+ close(fd1[1]); close(fd2[0]);
+
+ if (sys_dup2(fd1[0], STDIN_FILENO) != STDIN_FILENO) {
+ DEBUG(3,("could not redirect stdin\n"));
+ exit(83);
+ }
+ if (sys_dup2(fd2[1], STDOUT_FILENO) != STDOUT_FILENO) {
+ DEBUG(3,("could not redirect stdout\n"));
+ exit(84);
+ }
+ fd_null = open("/dev/null", O_WRONLY);
+ if (fd_null >= 0 ) {
+ if (sys_dup2(fd_null, STDERR_FILENO) != STDERR_FILENO) {
+ DEBUG(3,("could not redirect stderr\n"));
+ exit(85);
+ }
+ close(fd_null);
+ }
+ DEBUG(5,("child stdin/out/err redirection - done\n"));
+
+ gain_root_privilege();
+ gain_root_group_privilege();
+ DEBUG(5,("gained root uid/gid privilege\n"));
+
+ DEBUG(5,("running command %s\n", cmdname));
+ execl("/bin/sh", "sh", "-c", cmdname, NULL);
+
+ /* not reached */
+ exit(86);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ /* not reached */
+ return NT_STATUS_ACCESS_DENIED;
+}
+
+
+
+/**@ingroup password-quality
+ * Pre security check function. Checks for CTRL chars.
+ *
+ * @param username The username requesting password change
+ *
+ * @param fullname The fullename of the username requesting password change
+ *
+ * @param new_password The user's new password
+ *
+ * @return NTSTATUS
+ *
+*/
+static NTSTATUS pre_chk(const char *username, const char *fullname,
+ char *new_password)
+{
+
+ /* avoid injection attacks */
+ if (strhasctrl(new_password)) {
+ DEBUG(0,("new password contains ctrl char\n"));
+ return NT_STATUS_ILL_FORMED_PASSWORD;
+ }
+ if (strhasctrl(username)) {
+ DEBUG(0,("username contains ctrl char\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ if (strhasctrl(fullname)) {
+ DEBUG(0,("fullname contains ctrl char\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+
+/**@ingroup password-quality
+ * Returns the 'hex' value of a char.
+ *
+ * @param ascii character to convert to hex value
+ *
+ * @return the hex value of the ascii parameter
+ *
+*/
+static char ascii2hex(char ascii)
+{
+ return( (ascii <= '9') ? (ascii - '0') : (ascii - ('A' - 0x0A)));
+}
+
+
+
+/**@ingroup password-quality
+ * Convert a "0x 32bits string" (0x87654321) to uint32.
+ *
+ * @param strx string to be converted to uint32
+ *
+ * @param hex32 uint32 pointer to save the result
+ *
+ * @return 0 if no error / -1 on error
+ *
+*/
+static int ZEROxStr2uint32(char *strx, uint32 *hex32)
+{
+ char *onehex;
+
+ if (!strx)
+ return(-1);
+
+ if (strlen(strx) > 10 || StrnCaseCmp(strx, "0x", 2)) {
+ return(-1);
+ }
+
+ *hex32 = 0x00000000;
+ for(onehex = &strx[2]; *onehex != '\0'; onehex++) {
+
+ *onehex = toupper(*onehex);
+ if (!((*onehex >= '0') && (*onehex <= '9') ||
+ (*onehex >= 'A') && (*onehex <= 'F'))) {
+ return(-1);
+ }
+ *hex32 = (*hex32 << 4) | (uint32)ascii2hex(*onehex);
+
+ }
+ return(0);
+}
+
+
+
+/**@ingroup password-quality
+ * Check if string has a CNTRL character.
+ *
+ * @param str string to be converted to uint32
+ *
+ * @return BOOL Return True if found a CNTRL character, otherwise
+ * return False.
+ *
+*/
+static BOOL strhasctrl(const char *str) {
+
+ int i, len;
+
+ len = strlen(str);
+ for (i = 0; i < len; i++) {
+ if (iscntrl((int)str[i])) {
+ return True;
+ }
+ }
+ return False;
+}
--- source/smbd/chgpasswd.c Mon May 5 09:27:11 2003
+++ ../samba-head-work/source/smbd/chgpasswd.c Mon May 5 09:29:58 2003
@@ -745,7 +745,6 @@
uchar * ntdata, uchar * nthash)
{
fstring new_passwd;
- const char *unix_user;
SAM_ACCOUNT *sampass = NULL;
NTSTATUS nt_status
= check_oem_password(user, lmdata, lmhash, ntdata, nthash,
@@ -763,8 +762,6 @@
* available. JRA.
*/
- unix_user = pdb_get_username(sampass);
-
nt_status = change_oem_password(sampass, NULL, new_passwd);
memset(new_passwd, 0, sizeof(new_passwd));
@@ -948,6 +945,7 @@
{
BOOL ret;
uint32 min_len;
+ NTSTATUS ntresult;
if (time(NULL) < pdb_get_pass_can_change_time(hnd)) {
DEBUG(1, ("user %s cannot change password now, must wait until %s\n",
@@ -973,7 +971,11 @@
/* return NT_STATUS_PWD_TOO_SHORT; */
}
- /* TODO: Add cracklib support here */
+ /* Check for weak passwords */
+ ntresult = password_quality(hnd, new_passwd);
+ if ( ! NT_STATUS_IS_OK(ntresult)) {
+ return ntresult;
+ }
/*
* If unix password sync was requested, attempt to change
-------------- next part --------------
--- smb.conf.5.sgml Mon May 5 13:27:15 2003
+++ smb.conf.5.sgml.new Mon May 5 13:26:25 2003
@@ -722,6 +722,7 @@
<listitem><para><link linkend="PASSWDCHATDEBUG"><parameter>passwd chat debug</parameter></link></para></listitem>
<listitem><para><link linkend="PASSWDPROGRAM"><parameter>passwd program</parameter></link></para></listitem>
<listitem><para><link linkend="PASSWORDLEVEL"><parameter>password level</parameter></link></para></listitem>
+ <listitem><para><link linkend="PASSWORDQUALITY"><parameter>password quality script</parameter></link></para></listitem>
<listitem><para><link linkend="PASSWORDSERVER"><parameter>password server</parameter></link></para></listitem>
<listitem><para><link linkend="PREFEREDMASTER"><parameter>prefered master</parameter></link></para></listitem>
<listitem><para><link linkend="PREFERREDMASTER"><parameter>preferred master</parameter></link></para></listitem>
@@ -5667,6 +5668,100 @@
<para>Default: <command>password level = 0</command></para>
<para>Example: <command>password level = 4</command></para>
+ </listitem>
+ </varlistentry>
+
+
+
+ <varlistentry>
+ <term><anchor id="PASSWORDQUALITYSCRIPT">password quality script (G)</term>
+ <listitem><para>Full path to the script that will be called
+ when a request for change password is received. It will be run
+ by smbd as user & group ID "root".</para>
+
+ <para>The script is responsible to accept or refuse the new
+ password based on its own rules. As an example, it can be a
+ script refusing a weak password based on a dictionary word.</para>
+
+ <para>Samba back end communicates with the password quality
+ program by writing data to its STDIN and reading data from its
+ STDOUT. Samba writes a block of data in "Field: value\n"
+ terminated by a ".\n" at the beginning of a new line.</para>
+
+ <para>1) smbd ---> to Password quality script STDIN</para>
+ <screen>
+ <computeroutput>
+Version: Password-quality-protocol-version\n
+ Username: username\n
+ Fullname: fullname\n
+ Password: new-password\n
+ .\n
+ </computeroutput>
+ </screen>
+
+ <para>The above fields are filled with their respective value.
+ Once smbd writes on the last line ".\n", it waits from the
+ script, child process, its response and exit status. If there
+ is still no response after 15 seconds, a SIGTERM is sent
+ to the child process. smbd will then wait no more than 2
+ seconds to get the child's exit status otherwise a SIGKILL
+ is sent to the child process.</para>
+
+ <para>IMPORTANT NOTES: The "password-quality-protocol-version"
+ is an integer value. This value will be increased when changes
+ are made to Samba's <--> Password quality script protocol.
+ The "new-password" may have a leading or trailing space -- be
+ very carefull when parsing the data.</para>
+
+ <para>2) Password quality script STDOUT ---> to smbd</para>
+ <screen>
+ <computeroutput>
+NTStatus: ntstatus-string\n
+ Result: result-string\n
+ .\n
+ </computeroutput>
+ </screen>
+
+ <para>The "ntstatus-string" value can either use one the
+ pre-defined NTSTATUS (nterr.h) values. For this context:</para>
+
+ <para>NT_STATUS_OK # New password accepted</para>
+ <para>NT_STATUS_ACCESS_DENIED # An error occured</para>
+ <para>NT_STATUS_PASSWORD_RESTRICTION # Too short, too weak, etc</para>
+
+ <para>OR<para>
+
+ The "ntstatus-string" value can be an hex value represented by
+ a string. For example, the NT_STATUS_ACCESS_DENIED hex value is
+ 0xC0000022.
+
+ <para>The "result-string" value is used to provide information
+ (debug info) to smbd. For examples:</para>
+
+ <screen>
+ <computeroutput>
+NTStatus: NT_STATUS_PASSWORD_RESTRICTION\n
+ Result: Password is based on dictionary word\n
+ .\n
+
+ or
+
+ NTStatus: 0x0\n
+ Result: New password is accepted\n
+ .\n
+
+ </computeroutput>
+ </screen>
+
+ <para>To mark the end of communication, a ".\n" on the beginning
+ of a new line is required.</para>
+ <para>smbd will always return an error to the client and will
+ not change the current password unless the NTStatus value is
+ equal to "NT_STATUS_OK" AND the exit status of the script is
+ equal to 0.</para>
+
+ <para>Default: <command>password quality script = <empty string></command></para>
+ <para>Example: <command>password quality script = /usr/local/samba/sbin/password-quality.pl</command></para>
</listitem>
</varlistentry>
More information about the samba-technical
mailing list