New GPL'ed obscure.c replacement

Bernhard Fischer rep.nop at aon.at
Wed Jan 18 15:12:09 UTC 2006


On Wed, Jan 18, 2006 at 02:46:06PM +0100, Tito wrote:
>Hi to all,
>this is a proposal to substitute obscure.c with a new GPL'ed version.
>This is just a proof of concept for auditing and review by the list members.
>This version is more restrictive than the previous ( maybe to much?)

What about a
config CONFIG_PASSWD_STRENGTH
	bool "  minimal strength for new password"
	depends on CONFIG_PASSWORD
	default 2
	range 0 4
	help
	  0 .. don't check strength of password
	  1 .. at least one different kind of character class
	  2 .. at least two different kinds of character classes
	  3 .. at least three different kinds of character classes
	  4 .. at least four different kinds of character classes
	  
	  A character class is one of
	   - capital letter
	   - lowercase letter
	   - number
	   - other (none of the above)

That way it could be small if no checking was requested.

Just an idea

>and doesn't allow passwords that do not contain all four types
>of characters: upper,  lower, digits and special chars.
>Size is:
>
>root at localhost:/dev/pts/2:/root/Desktop/busybox/libbb# size obscure.o.orig
>   text    data     bss     dec     hex filename
>    757       0       0     757     2f5 obscure.o.orig
>   text    data     bss     dec     hex filename
>    667       0       0     667     29b obscure.o
>
>Comments, critics and improvements are as always welcome.
>
>BTW: as this function is used only by passwd.c I think this file
>          should be moved from libbb/ to loginutils/ dir.

Moving it to loginutils would be fine with me.

>
>Thanks in advance for your time and help.
>Ciao,
>Tito
>

>/* vi: set sw=4 ts=4: */
>/*
> * Mini weak password checker implementation for busybox
> *
> * Copyright (C) 2006 Tito Ragusa <farmatito at tiscali.it>
> *
> * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
> */
>
>/*	A good password:
>    1) should contain at least six characters (man passwd) so empty passwords are not permitted
>    2) should contain a mix of four different types of characters
>       upper case letters,
>       lower case letters,
>       numbers, 
>       special characters such as !@#$%^&*,;"
>       so this password types are not permitted:
>            a) pure numbers: birthdates,
>                             social security number,
>                             license plate,
>                             phone numbers;
>            b) words and all letters only passwords (uppercase, lowercase or mixed)
>               as palindromes, consecutive or repetitive letters 
>               or adjacent letters on your keyboard;
>       also not permitted are:
>            c) username, real name, company name or (e-mail?) address
>               in any form (as-is, reversed, capitalized, doubled, etc.).
>               (we can check only against username, gecos and hostname)
>
>       CAVEAT: we cannot check for this without the use of dictionaries:
>            d) common and obvious letter-number replacements 
>               (e.g. replace the letter O with number 0)
>               such as "M1cr0$0ft" or "P at ssw0rd".
>*/
>
>#include <ctype.h>
>#include <unistd.h>
>#include <string.h>
>
>#include "libbb.h"
>
>#define MINLEN 6

I think empty passwords should be allowed too, at least optional. YMMV.
>
>static int string_checker_helper(const char *p1, const char *p2)
perhaps attribute_pure
>{
>	/* as-is or capitalized */
>	if (strcasecmp(p1, p2) == 0
>	/* as sub-string */
>	|| strcasestr(p2, p1) != NULL
>	/* invert in case haystack is shorter than needle */
>	|| strcasestr(p1, p2) != NULL)
>		return 1;
>	return 0;
>}
>
>static int string_checker(const char *p1, const char *p2)
>{
>	int size;
>	/* check string */
>	int ret = string_checker_helper(p1, p2);
>	/* Make our own copy */
>	char *p = bb_xstrdup(p1);
>	/* reverse string */
>	size = strlen(p);
>
>	while(size--) {
>		*p = p1[size];
>		p++;
>	}
>	/* restore pointer */
>	p -= strlen(p1);
>	/* check reversed string */
>	ret |= string_checker_helper(p, p2);
>	/* clean up */
>	memset(p, 0, strlen(p));
>	free(p);
>	return ret;
>}
>
>#define LOWERCASE          1
>#define UPPERCASE          2
>#define NUMBERS            4
>#define SPECIAL            8
>
>static const char *obscure_msg(const char *old_p, const char *new_p, const struct passwd *pw) 
>{
>	int i;
>	int c;
>	int mixed = 0;
>	const char *p;
>	char hostname[255];
>
>	/* size */
>	if (!new_p || strlen(new_p) < MINLEN) return("to short");
s/to/too/
>	
>	/* no username as-is, as sub-string, reversed, capitalized, doubled */
>	if (string_checker(new_p, pw->pw_name))  return "similar to username";
>	/* no gecos    as-is, as sub-string, reversed, capitalized, doubled */
>	if (string_checker(new_p, pw->pw_gecos)) return "similar to gecos";
>	/* hostname    as-is, as sub-string, reversed, capitalized, doubled */
>	if(gethostname(hostname, 255) == 0) {
>		if (string_checker(new_p, hostname)) return "similar to hostname";
>	}
>	/* Must contain a mix of: */
>	for (i = 0; i < strlen(new_p); i++) {
>#if 0
>		/* Forbbidden chars: is this needed? */
>		if ( new_p[i] < 32 || new_p[i] == 126 ) /* Can we allow space ? new_p[i] == 33 */

space is ok, i think.

>			return "contains illegal characters";
>#endif
>		/* lowercase */
>		if (islower(new_p[i])) /* a-z */
>			mixed |= LOWERCASE;
>		/* uppercase */
>		else if (isupper(new_p[i])) /* A-Z */
>			mixed |= UPPERCASE;
>		/* numbers */
>		else if (isdigit(new_p[i])) /* 0-9 */
>			mixed |= NUMBERS;
>		/* special characters */
>		else
>			mixed |= SPECIAL;
>		
>		/* More than 50% similar characters? */
>		c = 0;
>		p = new_p;
>		while (1) {
>			if ((p = strchr(p, new_p[i])) == NULL) break;

Look at .indent.pro; the "break" should go on it's own line, iirc.
>			c++;
>			if (!++p) break; /* move past the matched char if possible */
>		}
>
>		if (c >= (strlen(new_p) / 2)) return "to much similar characters";
s/to much/too many/
>	}
>
>	if (mixed < 15) return "to weak";
s/to /too /g;# also: put return into a new line. This makes the code
more readable..
>	
>	if (old_p && old_p[0] != '\0') {
>		/* check vs. old password */
>		if (string_checker(new_p, old_p)) return "similar to old password";
>	}
>
>	return NULL;
>}
>
>extern int obscure(const char *old, const char *newval, const struct passwd *pwdp)
>{
>	const char *msg = obscure_msg(old, newval, pwdp);
>
>	if (msg != NULL) {
>		printf("Bad password: %s.\n", msg);
>		return 1;
>	}
>	return 0;
>}
>
>
>/* END CODE */
>/*
>Local Variables:
>c-file-style: "linux"
>c-basic-offset: 4
>tab-width: 4
>End:
>*/

Looks nice from a short glance :)



More information about the busybox mailing list