File chkname-regex.patch of Package shadow.8622

Index: lib/getdef.c
===================================================================
--- lib/getdef.c.orig
+++ lib/getdef.c
@@ -77,6 +77,7 @@ struct itemdef {
 
 #define NUMDEFS	(sizeof(def_table)/sizeof(def_table[0]))
 static struct itemdef def_table[] = {
+	{"CHARACTER_CLASS", NULL},
 	{"CHFN_RESTRICT", NULL},
 	{"CONSOLE_GROUPS", NULL},
 	{"CONSOLE", NULL},
Index: libmisc/chkname.c
===================================================================
--- libmisc/chkname.c.orig
+++ libmisc/chkname.c
@@ -43,30 +43,57 @@
 #ident "$Id$"
 
 #include <ctype.h>
+#include <regex.h>
 #include "defines.h"
 #include "chkname.h"
+#include "getdef.h"
+#include <stdio.h>
 
 static bool is_valid_name (const char *name)
 {
-	/*
-	 * User/group names must match [a-z_][a-z0-9_-]*[$]
-	 */
-	if (('\0' == *name) ||
-	    !((('a' <= *name) && ('z' >= *name)) || ('_' == *name))) {
+	const char *class;
+	regex_t reg;
+	int result;
+	char *buf;
+
+	/* User/group names must match [A-Za-z_][A-Za-z0-9_-.]*[A-Za-z0-9_-.$]?.
+	   This is the POSIX portable character class. The $ at the end is
+	   needed for SAMBA. But user can also specify something else in
+	   /etc/login.defs.  */
+	class = getdef_str ("CHARACTER_CLASS");
+	if (!class)
+		class = "[a-z_][a-z0-9_.-]*[a-z0-9_.$-]\\?";
+
+	if (asprintf (&buf, "^%s$", class) < 0)
+		return -1;
+
+	memset (&reg, 0, sizeof (regex_t));
+	result = regcomp (&reg, buf, 0);
+	free (buf);
+
+	if (result) {
+		size_t length = regerror (result, &reg, NULL, 0);
+		char *buffer = malloc (length);
+		if (buffer == NULL)
+			fputs ("running out of memory!\n", stderr);
+
+		/* else
+		   {
+		   regerror (result, &reg, buffer, length);
+		   fprintf (stderr, _("Can't compile regular expression: %s\n"),
+		   buffer);
+		   } */
+
+		regfree(&reg);
 		return false;
 	}
 
-	while ('\0' != *++name) {
-		if (!(( ('a' <= *name) && ('z' >= *name) ) ||
-		      ( ('0' <= *name) && ('9' >= *name) ) ||
-		      ('_' == *name) ||
-		      ('-' == *name) ||
-		      ( ('$' == *name) && ('\0' == *(name + 1)) )
-		     )) {
-			return false;
-		}
+	if (regexec (&reg, name, 0, NULL, 0) != 0) {
+		regfree(&reg);
+		return false;
 	}
 
+	regfree(&reg);
 	return true;
 }