svn commit: samba r2329 - in trunk/source: lib param rpc_server smbd

idra at samba.org idra at samba.org
Tue Sep 14 00:18:15 GMT 2004


Author: idra
Date: 2004-09-14 00:18:14 +0000 (Tue, 14 Sep 2004)
New Revision: 2329

WebSVN: http://websvn.samba.org/websvn/changeset.php?rep=samba&path=/trunk/source&rev=2329&nolog=1

Log:

Add facility to check password complexity with an external script


Modified:
   trunk/source/lib/smbrun.c
   trunk/source/param/loadparm.c
   trunk/source/rpc_server/srv_samr_nt.c
   trunk/source/smbd/chgpasswd.c


Changeset:
Modified: trunk/source/lib/smbrun.c
===================================================================
--- trunk/source/lib/smbrun.c	2004-09-13 14:17:41 UTC (rev 2328)
+++ trunk/source/lib/smbrun.c	2004-09-14 00:18:14 UTC (rev 2329)
@@ -90,7 +90,7 @@
 			*outfd = -1;
 		}
 		return errno;
-    }
+	}
 
 	if (pid) {
 		/*
@@ -178,3 +178,124 @@
 	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;
+}

Modified: trunk/source/param/loadparm.c
===================================================================
--- trunk/source/param/loadparm.c	2004-09-13 14:17:41 UTC (rev 2328)
+++ trunk/source/param/loadparm.c	2004-09-14 00:18:14 UTC (rev 2329)
@@ -158,6 +158,7 @@
 	char *szAddMachineScript;
 	char *szShutdownScript;
 	char *szAbortShutdownScript;
+	char *szCheckPasswordScript;
 	char *szWINSHook;
 	char *szWINSPartners;
 	char *szUtmpDir;
@@ -815,6 +816,7 @@
 	{"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}, 
@@ -1705,6 +1707,8 @@
 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)

Modified: trunk/source/rpc_server/srv_samr_nt.c
===================================================================
--- trunk/source/rpc_server/srv_samr_nt.c	2004-09-13 14:17:41 UTC (rev 2328)
+++ trunk/source/rpc_server/srv_samr_nt.c	2004-09-14 00:18:14 UTC (rev 2329)
@@ -2280,7 +2280,7 @@
 
 		if (add_script[0] != '\0') {
   			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);
   		}
 		else	/* no add user script -- ask winbindd to do it */
@@ -3698,7 +3698,7 @@
 	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));
 

Modified: trunk/source/smbd/chgpasswd.c
===================================================================
--- trunk/source/smbd/chgpasswd.c	2004-09-13 14:17:41 UTC (rev 2328)
+++ trunk/source/smbd/chgpasswd.c	2004-09-14 00:18:14 UTC (rev 2329)
@@ -1046,6 +1046,19 @@
 		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



More information about the samba-cvs mailing list