r2331: check password script code and example from trunk
authorSimo Sorce <idra@samba.org>
Tue, 14 Sep 2004 00:21:11 +0000 (00:21 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 15:52:39 +0000 (10:52 -0500)
examples/auth/crackcheck/Makefile [new file with mode: 0644]
examples/auth/crackcheck/crackcheck.c [new file with mode: 0644]
source/lib/smbrun.c
source/param/loadparm.c
source/rpc_server/srv_samr_nt.c
source/smbd/chgpasswd.c

diff --git a/examples/auth/crackcheck/Makefile b/examples/auth/crackcheck/Makefile
new file mode 100644 (file)
index 0000000..84377aa
--- /dev/null
@@ -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 (file)
index 0000000..3384337
--- /dev/null
@@ -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);
+
+}
+
index 592543bc43be89dc7fd8ab722a7145f00bd7c401..43cb209174e29f9ff2ae0141bd28a8e7c5580e50 100644 (file)
@@ -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;
+}
index 14981b97c4203cb222061bc92c1f4efd650a1799..24811af37ddf7eb8c91ba378fe1f4a2284dd12dd 100644 (file)
@@ -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)
index ce6d9dd37ec4f323d0dcbc15c8c5870f56844a60..74f6030365d8ff628e94d68751ce0a98000c9256 100644 (file)
@@ -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));
 
index 8ea5b9c60a3c37c093f77b04603b0e4a22ff4ef4..7d3ffedec0e04c1120c0c00cedfacd555b66e129 100644 (file)
@@ -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