summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/auth/crackcheck/Makefile25
-rw-r--r--examples/auth/crackcheck/crackcheck.c62
-rw-r--r--source3/lib/smbrun.c123
-rw-r--r--source3/param/loadparm.c4
-rw-r--r--source3/rpc_server/srv_samr_nt.c4
-rw-r--r--source3/smbd/chgpasswd.c13
6 files changed, 228 insertions, 3 deletions
diff --git a/examples/auth/crackcheck/Makefile b/examples/auth/crackcheck/Makefile
new file mode 100644
index 00000000000..84377aafefe
--- /dev/null
+++ b/examples/auth/crackcheck/Makefile
@@ -0,0 +1,25 @@
+# C compiler
+#CC=cc
+CC=gcc
+
+# Uncomment the following to add symbols to the code for debugging
+#DEBUG=-g -Wall
+
+# Optimization for the compiler
+#OPTIMIZE=
+OPTIMIZE=-O2
+
+CFLAGS= $(DEBUG) $(OPTIMIZE)
+
+OBJS = crackcheck.o
+LIBS = -lcrack
+
+crackcheck: $(OBJS)
+ $(CC) $(CFLAGS) $(LIBS) -o crackcheck $(OBJS)
+
+clean:
+ rm -f core *.o crackcheck
+
+install: crackcheck
+ install -m 555 crackcheck $(PREFIX)/sbin/crackcheck
+
diff --git a/examples/auth/crackcheck/crackcheck.c b/examples/auth/crackcheck/crackcheck.c
new file mode 100644
index 00000000000..338433779b0
--- /dev/null
+++ b/examples/auth/crackcheck/crackcheck.c
@@ -0,0 +1,62 @@
+#include <memory.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <crack.h>
+
+void usage(char *command) {
+ char *c, *comm;
+
+ comm = command;
+ while ((c = strrchr(comm, '/')) != NULL) {
+ comm = c + 1;
+ }
+
+ fprintf(stderr, "Usage: %s -d dictionary\n\n", comm);
+ fprintf(stderr, " -d dictionary file for cracklib\n\n");
+ fprintf(stderr, " The password is expected to be given via stdin.\n\n");
+ exit(-1);
+}
+
+int main(int argc, char **argv) {
+ extern char *optarg;
+ int c;
+
+ char f[256];
+ char *dictionary = NULL;
+ char *password;
+ char *reply;
+
+ while ( (c = getopt(argc, argv, "d:")) != EOF){
+ switch(c) {
+ case 'd':
+ dictionary = strdup(optarg);
+ break;
+ default:
+ usage(argv[0]);
+ }
+ }
+
+ if (dictionary == NULL) {
+ fprintf(stderr, "ERR - Wrong Command Line\n\n");
+ usage(argv[0]);
+ }
+
+ password = fgets(f, sizeof(f), stdin);
+
+ if (password == NULL) {
+ fprintf(stderr, "ERR - Failed to read password\n\n");
+ exit(-2);
+ }
+
+ reply = FascistCheck(password, dictionary);
+ if (reply != NULL) {
+ fprintf(stderr, "ERR - %s\n\n", reply);
+ exit(-3);
+ }
+
+ exit(0);
+
+}
+
diff --git a/source3/lib/smbrun.c b/source3/lib/smbrun.c
index 592543bc43b..43cb209174e 100644
--- a/source3/lib/smbrun.c
+++ b/source3/lib/smbrun.c
@@ -90,7 +90,7 @@ int smbrun(char *cmd, int *outfd)
*outfd = -1;
}
return errno;
- }
+ }
if (pid) {
/*
@@ -178,3 +178,124 @@ int smbrun(char *cmd, int *outfd)
exit(82);
return 1;
}
+
+
+/****************************************************************************
+run a command being careful about uid/gid handling and putting the output in
+outfd (or discard it if outfd is NULL).
+sends the provided secret to the child stdin.
+****************************************************************************/
+
+int smbrunsecret(char *cmd, char *secret)
+{
+ pid_t pid;
+ uid_t uid = current_user.uid;
+ gid_t gid = current_user.gid;
+ int ifd[2];
+
+ /*
+ * Lose any kernel oplock capabilities we may have.
+ */
+ oplock_set_capability(False, False);
+
+ /* build up an input pipe */
+ if(pipe(ifd)) {
+ return -1;
+ }
+
+ /* in this method we will exec /bin/sh with the correct
+ arguments, after first setting stdout to point at the file */
+
+ /*
+ * We need to temporarily stop CatchChild from eating
+ * SIGCLD signals as it also eats the exit status code. JRA.
+ */
+
+ CatchChildLeaveStatus();
+
+ if ((pid=sys_fork()) < 0) {
+ DEBUG(0, ("smbrunsecret: fork failed with error %s\n", strerror(errno)));
+ CatchChild();
+ return errno;
+ }
+
+ if (pid) {
+ /*
+ * Parent.
+ */
+ int status = 0;
+ pid_t wpid;
+
+ close(ifd[0]);
+ /* send the secret */
+ write(ifd[1], secret, strlen(secret));
+ fsync(ifd[1]);
+ close(ifd[1]);
+
+ /* the parent just waits for the child to exit */
+ while((wpid = sys_waitpid(pid, &status, 0)) < 0) {
+ if(errno == EINTR) {
+ errno = 0;
+ continue;
+ }
+ break;
+ }
+
+ CatchChild();
+
+ if (wpid != pid) {
+ DEBUG(2, ("waitpid(%d) : %s\n", (int)pid, strerror(errno)));
+ return -1;
+ }
+
+#if defined(WIFEXITED) && defined(WEXITSTATUS)
+ if (WIFEXITED(status)) {
+ return WEXITSTATUS(status);
+ }
+#endif
+
+ return status;
+ }
+
+ CatchChild();
+
+ /* we are in the child. we exec /bin/sh to do the work for us. we
+ don't directly exec the command we want because it may be a
+ pipeline or anything else the config file specifies */
+
+ close(ifd[1]);
+ close(0);
+ if (sys_dup2(ifd[0], 0) != 0) {
+ DEBUG(2,("Failed to create stdin file descriptor\n"));
+ close(ifd[0]);
+ exit(80);
+ }
+
+ /* now completely lose our privileges. This is a fairly paranoid
+ way of doing it, but it does work on all systems that I know of */
+
+ become_user_permanently(uid, gid);
+
+ if (getuid() != uid || geteuid() != uid ||
+ getgid() != gid || getegid() != gid) {
+ /* we failed to lose our privileges - do not execute
+ the command */
+ exit(81); /* we can't print stuff at this stage,
+ instead use exit codes for debugging */
+ }
+
+#ifndef __INSURE__
+ /* close all other file descriptors, leaving only 0, 1 and 2. 0 and
+ 2 point to /dev/null from the startup code */
+ {
+ int fd;
+ for (fd = 3; fd < 256; fd++) close(fd);
+ }
+#endif
+
+ execl("/bin/sh", "sh", "-c", cmd, NULL);
+
+ /* not reached */
+ exit(82);
+ return 1;
+}
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index 14981b97c42..24811af37dd 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -156,6 +156,7 @@ typedef struct
char *szAddMachineScript;
char *szShutdownScript;
char *szAbortShutdownScript;
+ char *szCheckPasswordScript;
char *szWINSHook;
char *szWINSPartners;
char *szUtmpDir;
@@ -811,6 +812,7 @@ static struct parm_struct parm_table[] = {
{"passwd chat", P_STRING, P_GLOBAL, &Globals.szPasswdChat, NULL, NULL, FLAG_ADVANCED},
{"passwd chat debug", P_BOOL, P_GLOBAL, &Globals.bPasswdChatDebug, NULL, NULL, FLAG_ADVANCED},
{"passwd chat timeout", P_INTEGER, P_GLOBAL, &Globals.iPasswdChatTimeout, NULL, NULL, FLAG_ADVANCED},
+ {"check password script", P_STRING, P_GLOBAL, &Globals.szCheckPasswordScript, NULL, NULL, FLAG_ADVANCED},
{"username map", P_STRING, P_GLOBAL, &Globals.szUsernameMap, NULL, NULL, FLAG_ADVANCED},
{"password level", P_INTEGER, P_GLOBAL, &Globals.pwordlevel, NULL, NULL, FLAG_ADVANCED},
{"username level", P_INTEGER, P_GLOBAL, &Globals.unamelevel, NULL, NULL, FLAG_ADVANCED},
@@ -1678,6 +1680,8 @@ FN_GLOBAL_STRING(lp_addmachine_script, &Globals.szAddMachineScript)
FN_GLOBAL_STRING(lp_shutdown_script, &Globals.szShutdownScript)
FN_GLOBAL_STRING(lp_abort_shutdown_script, &Globals.szAbortShutdownScript)
+FN_GLOBAL_STRING(lp_check_password_script, &Globals.szCheckPasswordScript)
+
FN_GLOBAL_STRING(lp_wins_hook, &Globals.szWINSHook)
FN_GLOBAL_STRING(lp_wins_partners, &Globals.szWINSPartners)
FN_GLOBAL_STRING(lp_template_primary_group, &Globals.szTemplatePrimaryGroup)
diff --git a/source3/rpc_server/srv_samr_nt.c b/source3/rpc_server/srv_samr_nt.c
index ce6d9dd37ec..74f6030365d 100644
--- a/source3/rpc_server/srv_samr_nt.c
+++ b/source3/rpc_server/srv_samr_nt.c
@@ -2240,7 +2240,7 @@ NTSTATUS _samr_create_user(pipes_struct *p, SAMR_Q_CREATE_USER *q_u, SAMR_R_CREA
if (*add_script) {
int add_ret;
- all_string_sub(add_script, "%u", account, sizeof(account));
+ all_string_sub(add_script, "%u", account, sizeof(add_script));
add_ret = smbrun(add_script,NULL);
DEBUG(3,("_samr_create_user: Running the command `%s' gave %d\n", add_script, add_ret));
}
@@ -3626,7 +3626,7 @@ static int smb_delete_user(const char *unix_user)
pstrcpy(del_script, lp_deluser_script());
if (! *del_script)
return -1;
- all_string_sub(del_script, "%u", unix_user, sizeof(pstring));
+ all_string_sub(del_script, "%u", unix_user, sizeof(del_script));
ret = smbrun(del_script,NULL);
DEBUG(3,("smb_delete_user: Running the command `%s' gave %d\n",del_script,ret));
diff --git a/source3/smbd/chgpasswd.c b/source3/smbd/chgpasswd.c
index 8ea5b9c60a3..7d3ffedec0e 100644
--- a/source3/smbd/chgpasswd.c
+++ b/source3/smbd/chgpasswd.c
@@ -1046,6 +1046,19 @@ NTSTATUS change_oem_password(SAM_ACCOUNT *hnd, char *old_passwd, char *new_passw
return NT_STATUS_ACCESS_DENIED;
}
+ /* Use external script to check password complexity */
+ if (lp_check_password_script()) {
+ int check_ret;
+
+ check_ret = smbrunsecret(lp_check_password_script(), new_passwd);
+ DEBUG(5, ("change_oem_password: check password script (%s) returned [%d]\n", lp_check_password_script(), check_ret));
+
+ if (check_ret != 0) {
+ DEBUG(1, ("change_oem_password: check password script said new password is not good enough!\n"));
+ return NT_STATUS_PASSWORD_RESTRICTION;
+ }
+ }
+
/*
* If unix password sync was requested, attempt to change
* the /etc/passwd database first. Return failure if this cannot