Some stuff that's been sitting in my tree for too long...
Improve the pw_policy(3) API by splitting it to two functions, one to load the policy from /etc/passwd.conf and another to test passwords against the policy. Some bug fixes, more consistent code, and man-page updates. Minor for libutil bumped.
This commit is contained in:
parent
cce659e230
commit
378a5a27de
|
@ -1,4 +1,4 @@
|
|||
# $NetBSD: shl.mi,v 1.336 2006/02/13 16:51:35 christos Exp $
|
||||
# $NetBSD: shl.mi,v 1.337 2006/02/18 10:52:48 elad Exp $
|
||||
# Note: libtermcap and libtermlib are hardlinked and share the same version.
|
||||
./lib/libc.so.12.136 base-sys-shlib
|
||||
./lib/libcrypt.so.0.2 base-sys-shlib
|
||||
|
@ -11,7 +11,7 @@
|
|||
./lib/libradius.so.1.0 base-sys-shlib
|
||||
./lib/libtermcap.so.0.6 base-sys-shlib
|
||||
./lib/libtermlib.so.0.6 base-sys-shlib
|
||||
./lib/libutil.so.7.8 base-sys-shlib
|
||||
./lib/libutil.so.7.9 base-sys-shlib
|
||||
./lib/libz.so.1.0 base-sys-shlib
|
||||
./usr/lib/i18n/libBIG5.so.4.4 base-i18n-shlib
|
||||
./usr/lib/i18n/libEUC.so.4.4 base-i18n-shlib
|
||||
|
@ -85,7 +85,7 @@
|
|||
./usr/lib/libtermcap.so.0.6 base-sys-shlib
|
||||
./usr/lib/libtermlib.so.0.6 base-sys-shlib
|
||||
./usr/lib/libusbhid.so.1.0 base-sys-shlib
|
||||
./usr/lib/libutil.so.7.8 base-sys-shlib
|
||||
./usr/lib/libutil.so.7.9 base-sys-shlib
|
||||
./usr/lib/libwrap.so.0.2 base-net-shlib
|
||||
./usr/lib/libz.so.1.0 base-sys-shlib
|
||||
./usr/lib/security/pam_afslog.so.0 base-sys-shlib kerberos,pam
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" $NetBSD: pw_policy.3,v 1.1 2005/09/14 11:36:52 elad Exp $
|
||||
.\" $NetBSD: pw_policy.3,v 1.2 2006/02/18 10:52:48 elad Exp $
|
||||
.\"
|
||||
.\" Copyright 2005 Elad Efrat <elad@NetBSD.org>
|
||||
.\" Copyright 2005, 2006 Elad Efrat <elad@NetBSD.org>
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
|
@ -23,10 +23,11 @@
|
|||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd September 13, 2005
|
||||
.Dd February 16, 2006
|
||||
.Dt PW_POLICY 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm pw_policy_load ,
|
||||
.Nm pw_policy_test
|
||||
.Nd password policy enforcement
|
||||
.Sh LIBRARY
|
||||
|
@ -34,19 +35,26 @@
|
|||
.Sh SYNOPSIS
|
||||
.In util.h
|
||||
.Ft int
|
||||
.Fn pw_policy_test "char *pw" "void *key" "int how"
|
||||
.Fn pw_policy_load "struct pw_policy *policy" "void *key" "int how"
|
||||
.Ft int
|
||||
.Fn pw_policy_test "struct pw_policy *policy" "char *pw"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Fn pw_policy_load
|
||||
and
|
||||
.Fn pw_policy_test
|
||||
function checks if the password passed in
|
||||
.Ar pw
|
||||
follows the system's password policy as specified in
|
||||
functions are used as an interface to the system's password policy
|
||||
as specified in
|
||||
.Pa /etc/passwd.conf .
|
||||
.Pp
|
||||
.Fn pw_policy_load
|
||||
will load a password policy into
|
||||
.Ar policy .
|
||||
.Pp
|
||||
Using
|
||||
.Xr pw_getconf 3
|
||||
terminology,
|
||||
.Fn pw_policy_test
|
||||
.Fn pw_policy_load
|
||||
accepts a
|
||||
.Ar key
|
||||
to be used when searching
|
||||
|
@ -59,25 +67,23 @@ To allow calling from various program contexts
|
|||
and using various password policy retrieval schemes,
|
||||
.Ar how
|
||||
tells
|
||||
.Fn pw_policy_test
|
||||
.Fn pw_policy_load
|
||||
how to treat
|
||||
.Ar key .
|
||||
.Pp
|
||||
The value of
|
||||
Possible values for
|
||||
.Ar how
|
||||
can be
|
||||
.Dv PW_POLICY_BYSTRING
|
||||
to indicate the passed
|
||||
are:
|
||||
.Pp
|
||||
.Bl -tag -width kungfuninja -compact
|
||||
.It Li PW_POLICY_BYSTRING
|
||||
.Ar key
|
||||
is to be used as a
|
||||
is used as a
|
||||
.Ft char * ,
|
||||
looking up the string it contains in
|
||||
.Pa /etc/passwd.conf .
|
||||
.Pp
|
||||
If
|
||||
.Ar how
|
||||
is
|
||||
.Dv PW_POLICY_BYPASSWD ,
|
||||
.It Li PW_POLICY_BYPASSWD
|
||||
.Ar key
|
||||
is used as a
|
||||
.Ft struct passwd * ,
|
||||
|
@ -86,16 +92,13 @@ first looking up the username in
|
|||
and if no key can be found, it will try the login class in
|
||||
.Ft pw_class .
|
||||
.Pp
|
||||
Using the value
|
||||
.Dv PW_POLICY_BYGROUP
|
||||
for
|
||||
.Ar how
|
||||
will use
|
||||
.It Li PW_POLICY_BYGROUP
|
||||
.Ar key
|
||||
as a
|
||||
is used as a
|
||||
.Ft struct group * ,
|
||||
looking up the group name in
|
||||
.Ft gr_name .
|
||||
.El
|
||||
.Pp
|
||||
If
|
||||
.Ar key
|
||||
|
@ -106,6 +109,12 @@ or no specified key can be found, the default key,
|
|||
is used.
|
||||
If even the default key can't be found,
|
||||
the password is accepted as no policy is defined.
|
||||
.Pp
|
||||
.Fn pw_policy_test
|
||||
can be used to check if the password in
|
||||
.Ar pw
|
||||
is compliant with the policy in
|
||||
.Ar policy .
|
||||
.Sh BUILT-IN POLICY SYNTAX
|
||||
Available built-in policy options include the following:
|
||||
.Pp
|
||||
|
@ -197,55 +206,69 @@ And that the user must change character class every 2 characters:
|
|||
ntoggles = *-2
|
||||
.Ed
|
||||
.Sh RETURN VALUES
|
||||
Upon success, meaning the password follows the specified policy,
|
||||
.Fn pw_policy_test
|
||||
will return 0.
|
||||
.Fn pw_policy_load
|
||||
returns 0 upon success, or any of the below errors upon failure:
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er ENOENT
|
||||
The
|
||||
.Pa /etc/passwd.conf
|
||||
is missing.
|
||||
.It Bq Er EFAULT
|
||||
NULL pointer passed for policy storage.
|
||||
.It Bq Er EINVAL
|
||||
Invalid value for the
|
||||
.Ar how
|
||||
parameter or an invalid value in the password policy specification.
|
||||
.El
|
||||
.Pp
|
||||
.Fn pw_policy_test
|
||||
will fail and return any of the following if:
|
||||
returns 0 if the password follows the policy, or any of the following
|
||||
values:
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er EPERM
|
||||
The password does not follow the specified policy.
|
||||
The password does not follow the password policy.
|
||||
.It Bq Er EFAULT
|
||||
The password string provided is
|
||||
.Dv NULL .
|
||||
.It Bq Er ENOENT
|
||||
.Pa /etc/passwd.conf
|
||||
could not be found.
|
||||
.It Bq Er EINVAL
|
||||
.Ar how
|
||||
has an invalid value.
|
||||
NULL pointer was passed as the password.
|
||||
.El
|
||||
.Pp
|
||||
In addition,
|
||||
.Fn pw_policy_load
|
||||
and
|
||||
.Fn pw_policy_test
|
||||
can also return any of the values returned by the called handlers.
|
||||
.Sh FILES
|
||||
.Bl -tag -width /etc/passwd.conf -compact
|
||||
.It Pa /etc/passwd.conf
|
||||
password configuration file.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
To check if
|
||||
.Ar the_password
|
||||
follows the system's default password policy:
|
||||
Initialize a password policy structure:
|
||||
.Bd -literal -offset indent
|
||||
error = pw_policy_test(the_password, NULL, 0);
|
||||
if (error == EPERM)
|
||||
(void)printf("Please refer to the password policy.\en");
|
||||
struct pw_policy policy = PW_POLICY_INIT;
|
||||
.Ed
|
||||
.Pp
|
||||
To check if
|
||||
.Ar the_password ,
|
||||
entered by a user whose password database entry is in
|
||||
.Ar pw_entry
|
||||
follows the specified policy:
|
||||
Load the system global password policy into
|
||||
.Ar policy :
|
||||
.Bd -literal -offset indent
|
||||
error = pw_policy_test(the_password, pw_entry, PW_POLICY_BYPASSWD);
|
||||
error = pw_policy_load(&policy, NULL, 0);
|
||||
if (error)
|
||||
errx(1, "Can't load password policy");
|
||||
.Ed
|
||||
.Pp
|
||||
Load a policy for a user whose password database entry is in
|
||||
.Ar pw_entry
|
||||
into
|
||||
.Ar policy :
|
||||
.Bd -literal -offset indent
|
||||
error = pw_policy_load(&policy, pw_entry, PW_POLICY_BYPASSWD);
|
||||
if (error == EPERM) {
|
||||
(void)printf("Please refer to the password policy.\en");
|
||||
warnx("Please refer to the password policy");
|
||||
return (EPERM);
|
||||
}
|
||||
.Ed
|
||||
.Pp
|
||||
Note that
|
||||
.Fn pw_policy_test
|
||||
.Fn pw_policy_load
|
||||
will first look for a password policy for the username in
|
||||
.Ar pw_entry-\*[Gt]pw_name ,
|
||||
if not found, it will try looking for a policy for the login class in
|
||||
|
@ -257,16 +280,33 @@ To handle cases where there is no
|
|||
.Pa /etc/passwd.conf ,
|
||||
it might be desired to fallback to an internal policy:
|
||||
.Bd -literal -offset indent
|
||||
error = pw_policy(the_password, NULL, 0);
|
||||
error = pw_policy_load(&policy, NULL, 0);
|
||||
if (error == ENOENT) {
|
||||
/* No /etc/passwd.conf. Just check minimum length. */
|
||||
if (strlen(the_password) \*[Lt] 8) {
|
||||
(void)printf("Please use at least 8 chars.\en");
|
||||
return (EPERM);
|
||||
}
|
||||
policy.minlen = 8;
|
||||
}
|
||||
.Ed
|
||||
.Pp
|
||||
Load the password policy for a group
|
||||
whose group database entry is in
|
||||
.Ar grent ,
|
||||
into
|
||||
.Ar policy :
|
||||
error = pw_policy_load(&policy, grent, PW_POLICY_BYGROUP);
|
||||
if (error)
|
||||
errx(1, "Can't load password policy for \"%s\"", grent-\*[Gt]gr_name);
|
||||
.Ed
|
||||
.Pp
|
||||
Check if
|
||||
.Ar the_password
|
||||
follows the policy in
|
||||
.Ar policy :
|
||||
.Bd -literal -offset indent
|
||||
error = pw_policy_test(&policy, the_password);
|
||||
if (error == EPERM)
|
||||
warnx("Please refer to the password policy");
|
||||
.Ed
|
||||
.Pp
|
||||
An example for a common default password policy in
|
||||
.Pa /etc/passwd.conf :
|
||||
.Bd -literal -offset indent
|
||||
|
@ -288,8 +328,10 @@ A different policy that might be used:
|
|||
.Xr passwd.conf 5
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
function first appeared in
|
||||
.Fn pw_policy_load
|
||||
and
|
||||
.Fn pw_policy_test
|
||||
functions first appeared in
|
||||
.Nx 4.0 .
|
||||
.Sh AUTHORS
|
||||
.An Elad Efrat
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* $NetBSD: pw_policy.c,v 1.2 2005/09/16 22:38:48 elad Exp $ */
|
||||
/* $NetBSD: pw_policy.c,v 1.3 2006/02/18 10:52:48 elad Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright 2005 Elad Efrat <elad@NetBSD.org>
|
||||
* Copyright 2005, 2006 Elad Efrat <elad@NetBSD.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
|
@ -41,26 +41,19 @@
|
|||
|
||||
#define PW_POLICY_DEFAULTKEY "pw_policy"
|
||||
|
||||
#define PW_GETCONF(buf, len, key, opt) \
|
||||
do { \
|
||||
memset(buf, 0, len); \
|
||||
pw_getconf(buf, len, key, opt); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
#define LOAD_POLICY 0
|
||||
#define TEST_POLICY 1
|
||||
|
||||
#define NEED_NONE 0
|
||||
#define NEED_ARG 1
|
||||
#define NEED_ARGS 2
|
||||
#define MINMAX_ERR(min, max, n) ((min == 0 || max == 0) && n != 0) || \
|
||||
(min > 0 && min > n) || \
|
||||
(max > 0 && max < n)
|
||||
|
||||
#define HANDLER_PROTO char *, size_t, void *, void *
|
||||
#define HANDLER_ARGS char *pw, size_t len, void *arg, void *arg2
|
||||
#define HANDLER_SANE(needarg) \
|
||||
((pw != NULL) && (len != 0) && \
|
||||
((/*CONSTCOND*/needarg == NEED_NONE) || \
|
||||
(/*CONSTCOND*/needarg == NEED_ARG && arg != NULL) || \
|
||||
(/*CONSTCOND*/needarg == NEED_ARGS && arg != NULL && arg2 != NULL)))
|
||||
#define HANDLER_PROTO struct pw_policy *, int, char *, void *, void *
|
||||
#define HANDLER_ARGS struct pw_policy *policy, int flag, char *pw, void *arg, void *arg2
|
||||
|
||||
static int pw_policy_parse_num(char *, int32_t *);
|
||||
static int pw_policy_parse_range(char *, int32_t *, int32_t *);
|
||||
|
||||
static int pw_policy_handle_len(HANDLER_PROTO);
|
||||
static int pw_policy_handle_charclass(HANDLER_PROTO);
|
||||
static int pw_policy_handle_nclasses(HANDLER_PROTO);
|
||||
|
@ -68,7 +61,7 @@ static int pw_policy_handle_ntoggles(HANDLER_PROTO);
|
|||
|
||||
struct pw_policy_handler {
|
||||
const char *name;
|
||||
int (*handler)(char *, size_t, void *, void *);
|
||||
int (*handler)(HANDLER_PROTO);
|
||||
void *arg2;
|
||||
};
|
||||
|
||||
|
@ -87,23 +80,26 @@ static int
|
|||
pw_policy_parse_num(char *s, int32_t *n)
|
||||
{
|
||||
char *endptr = NULL;
|
||||
unsigned long m;
|
||||
long l;
|
||||
|
||||
if (s == NULL || n == NULL)
|
||||
return (EFAULT);
|
||||
|
||||
m = strtoul(s, &endptr, 10);
|
||||
if (*endptr != '\0' || m == ULONG_MAX)
|
||||
return (EINVAL);
|
||||
if (s[0] == '*' && s[1] == '\0') {
|
||||
*n = -1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* We receive a signed 32-bit integer, but we only allow
|
||||
* unsigned 16-bit values.
|
||||
*/
|
||||
if (m >= (unsigned long)UINT16_MAX)
|
||||
l = strtol(s, &endptr, 10);
|
||||
if (*endptr != '\0')
|
||||
return (EINVAL);
|
||||
if (errno == ERANGE && (l == LONG_MIN || l == LONG_MAX))
|
||||
return (ERANGE);
|
||||
|
||||
*n = (int32_t)m;
|
||||
if (l < 0 || l >= UINT16_MAX)
|
||||
return (ERANGE);
|
||||
|
||||
*n = (int32_t)l;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -124,11 +120,11 @@ pw_policy_parse_range(char *range, int32_t *n, int32_t *m)
|
|||
|
||||
/* Single characters: * = any number, 0 = none. */
|
||||
if (range[0] == '0' && range[1] == '\0') {
|
||||
*n = *m = -1;
|
||||
*n = *m = 0;
|
||||
return (0);
|
||||
}
|
||||
if (range[0] == '*' && range[1] == '\0') {
|
||||
*n = *m = 0;
|
||||
*n = *m = -1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -152,25 +148,35 @@ pw_policy_parse_range(char *range, int32_t *n, int32_t *m)
|
|||
return (0);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
static int
|
||||
pw_policy_handle_len(HANDLER_ARGS)
|
||||
{
|
||||
int32_t n = 0, m = 0;
|
||||
switch (flag) {
|
||||
case LOAD_POLICY:
|
||||
/* Here, '0' and '*' mean the same. */
|
||||
if (pw_policy_parse_range(arg, &policy->minlen, &policy->maxlen) != 0)
|
||||
return (EINVAL);
|
||||
|
||||
if (!HANDLER_SANE(NEED_ARG))
|
||||
return (EFAULT);
|
||||
if (policy->minlen < 0)
|
||||
policy->minlen = 0;
|
||||
if (policy->maxlen < 0)
|
||||
policy->maxlen = 0;
|
||||
|
||||
/* Here, '0' and '*' mean the same. */
|
||||
if (pw_policy_parse_range(arg, &n, &m) != 0)
|
||||
return (EINVAL);
|
||||
break;
|
||||
|
||||
if (n < 0)
|
||||
n = 0;
|
||||
if (m < 0)
|
||||
m = 0;
|
||||
case TEST_POLICY: {
|
||||
size_t len;
|
||||
|
||||
if ((n && len < n) || (m && len > m))
|
||||
return (EPERM);
|
||||
len = strlen(pw);
|
||||
|
||||
if ((policy->minlen && len < policy->minlen) ||
|
||||
(policy->maxlen && len > policy->maxlen))
|
||||
return (EPERM);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -179,147 +185,175 @@ static int
|
|||
pw_policy_handle_charclass(HANDLER_ARGS)
|
||||
{
|
||||
int (*ischarclass)(int);
|
||||
int32_t n = 0, m = 0, count = 0;
|
||||
int32_t *n = NULL, *m = NULL, count = 0;
|
||||
|
||||
if (!HANDLER_SANE(NEED_ARGS))
|
||||
return (EFAULT);
|
||||
if (arg2 == islower) {
|
||||
n = &policy->minlower;
|
||||
m = &policy->maxlower;
|
||||
} else if (arg2 == isupper) {
|
||||
n = &policy->minupper;
|
||||
m = &policy->maxupper;
|
||||
} else if (arg2 == isdigit) {
|
||||
n = &policy->mindigits;
|
||||
m = &policy->maxdigits;
|
||||
} else if (arg2 == ispunct) {
|
||||
n = &policy->minpunct;
|
||||
m = &policy->maxpunct;
|
||||
}
|
||||
|
||||
if (pw_policy_parse_range(arg, &n, &m) != 0)
|
||||
return (EINVAL);
|
||||
switch (flag) {
|
||||
case LOAD_POLICY:
|
||||
if ((pw_policy_parse_range(arg, n, m) != 0))
|
||||
return (EINVAL);
|
||||
|
||||
ischarclass = arg2;
|
||||
break;
|
||||
|
||||
if (n == 0 && m == 0)
|
||||
return (0);
|
||||
case TEST_POLICY:
|
||||
ischarclass = arg2;
|
||||
|
||||
do {
|
||||
if (ischarclass((int)*pw++))
|
||||
count++;
|
||||
} while (*pw != '\0');
|
||||
do {
|
||||
if (!isspace((int)*pw) && ischarclass((int)*pw++))
|
||||
count++;
|
||||
} while (*pw != '\0');
|
||||
|
||||
if (n == -1 && count)
|
||||
return (EPERM);
|
||||
if (MINMAX_ERR(*n, *m, count))
|
||||
return (EPERM);
|
||||
|
||||
if ((n >= 0 && count < n) || (m >= 0 && count > m))
|
||||
return (EPERM);
|
||||
break;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
static int
|
||||
pw_policy_handle_nclasses(HANDLER_ARGS)
|
||||
{
|
||||
int have_lower = 0, have_upper = 0, have_digit = 0, have_punct = 0;
|
||||
int32_t n = 0, m = 0, nsets = 0;
|
||||
switch (flag) {
|
||||
case LOAD_POLICY:
|
||||
if (pw_policy_parse_range(arg, &policy->minclasses, &policy->maxclasses) != 0)
|
||||
return (EINVAL);
|
||||
|
||||
if (!HANDLER_SANE(NEED_ARG))
|
||||
return (EFAULT);
|
||||
break;
|
||||
|
||||
if (pw_policy_parse_range(arg, &n, &m) != 0)
|
||||
return (EINVAL);
|
||||
case TEST_POLICY: {
|
||||
int have_lower = 0, have_upper = 0, have_digit = 0, have_punct = 0;
|
||||
int32_t nsets = 0;
|
||||
|
||||
while (*pw != '\0') {
|
||||
if (islower((unsigned char)*pw) && !have_lower) {
|
||||
have_lower = 1;
|
||||
nsets++;
|
||||
} else if (isupper((unsigned char)*pw) && !have_upper) {
|
||||
have_upper = 1;
|
||||
nsets++;
|
||||
} else if (isdigit((unsigned char)*pw) && !have_digit) {
|
||||
have_digit = 1;
|
||||
nsets++;
|
||||
} else if (ispunct((unsigned char)*pw) && !have_punct) {
|
||||
have_punct = 1;
|
||||
nsets++;
|
||||
while (*pw != '\0') {
|
||||
if (islower((unsigned char)*pw) && !have_lower) {
|
||||
have_lower = 1;
|
||||
nsets++;
|
||||
} else if (isupper((unsigned char)*pw) && !have_upper) {
|
||||
have_upper = 1;
|
||||
nsets++;
|
||||
} else if (isdigit((unsigned char)*pw) && !have_digit) {
|
||||
have_digit = 1;
|
||||
nsets++;
|
||||
} else if (ispunct((unsigned char)*pw) && !have_punct) {
|
||||
have_punct = 1;
|
||||
nsets++;
|
||||
}
|
||||
pw++;
|
||||
}
|
||||
pw++;
|
||||
}
|
||||
|
||||
if ((n >= 0 && nsets < n) || (m >= 0 && nsets > m))
|
||||
return (EPERM);
|
||||
if (MINMAX_ERR(policy->minclasses, policy->maxclasses, nsets))
|
||||
return (EPERM);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
static int
|
||||
pw_policy_handle_ntoggles(HANDLER_ARGS)
|
||||
{
|
||||
int previous_set = 0, current_set = 0;
|
||||
int32_t n = 0, m = 0, ntoggles = 0;
|
||||
switch (flag) {
|
||||
case LOAD_POLICY:
|
||||
if (pw_policy_parse_range(arg, &policy->mintoggles, &policy->maxtoggles) != 0)
|
||||
return (EINVAL);
|
||||
|
||||
if (!HANDLER_SANE(NEED_ARG))
|
||||
return (EFAULT);
|
||||
break;
|
||||
|
||||
if (pw_policy_parse_range(arg, &n, &m) != 0)
|
||||
return (EINVAL);
|
||||
case TEST_POLICY: {
|
||||
int previous_set = 0, current_set = 0;
|
||||
int32_t ntoggles = 0, current_ntoggles = 0;
|
||||
|
||||
#define CHAR_CLASS(c) (islower((unsigned char)(c)) ? 1 : \
|
||||
isupper((unsigned char)(c)) ? 2 : \
|
||||
isdigit((unsigned char)(c)) ? 3 : \
|
||||
ispunct((unsigned char)(c)) ? 4 : \
|
||||
isupper((unsigned char)(c)) ? 2 : \
|
||||
isdigit((unsigned char)(c)) ? 3 : \
|
||||
ispunct((unsigned char)(c)) ? 4 : \
|
||||
0)
|
||||
|
||||
while (*pw != '\0') {
|
||||
current_set = CHAR_CLASS(*pw);
|
||||
if (!current_set) {
|
||||
return (EINVAL);
|
||||
}
|
||||
while (*pw != '\0') {
|
||||
if (!isspace((int)*pw)) {
|
||||
current_set = CHAR_CLASS(*pw);
|
||||
if (!current_set) {
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
if (!previous_set || current_set == previous_set) {
|
||||
ntoggles++;
|
||||
} else {
|
||||
ntoggles = 1;
|
||||
}
|
||||
if (!previous_set || current_set == previous_set) {
|
||||
current_ntoggles++;
|
||||
} else {
|
||||
if (current_ntoggles > ntoggles)
|
||||
ntoggles = current_ntoggles;
|
||||
|
||||
previous_set = current_set;
|
||||
pw++;
|
||||
}
|
||||
current_ntoggles = 1;
|
||||
}
|
||||
|
||||
previous_set = current_set;
|
||||
}
|
||||
|
||||
pw++;
|
||||
}
|
||||
|
||||
#undef CHAR_CLASS
|
||||
|
||||
if ((n >= 0 && ntoggles < n) || (m >= 0 && ntoggles > m))
|
||||
return (EPERM);
|
||||
if (MINMAX_ERR(policy->mintoggles, policy->maxtoggles, ntoggles))
|
||||
return (EPERM);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pw_policy_test(char *pw, void *key, int how)
|
||||
pw_policy_load(struct pw_policy *policy, void *key, int how)
|
||||
{
|
||||
struct pw_policy_handler *hp;
|
||||
char buf[BUFSIZ];
|
||||
size_t pwlen;
|
||||
|
||||
/*
|
||||
* No password provided, fail the test.
|
||||
*/
|
||||
if (pw == NULL)
|
||||
return (EFAULT);
|
||||
|
||||
/*
|
||||
* If there's no /etc/passwd.conf, we allow the password.
|
||||
*/
|
||||
/* If there's no /etc/passwd.conf, don't touch the policy. */
|
||||
if (access(_PATH_PASSWD_CONF, R_OK) == -1)
|
||||
return (ENOENT);
|
||||
|
||||
/*
|
||||
* No key provided. Use default.
|
||||
*/
|
||||
if (policy == NULL)
|
||||
return (EFAULT);
|
||||
|
||||
/* No key provided. Use default. */
|
||||
if (key == NULL) {
|
||||
key = __UNCONST(PW_POLICY_DEFAULTKEY);
|
||||
goto test_policies;
|
||||
goto load_policies;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
switch (how) {
|
||||
case PW_POLICY_BYSTRING:
|
||||
/*
|
||||
* Check for provided key. If non-existant, fallback to
|
||||
* the default.
|
||||
*/
|
||||
errno = 0;
|
||||
PW_GETCONF(buf, sizeof(buf), key, "foo");
|
||||
pw_getconf(buf, sizeof(buf), key, "foo");
|
||||
if (errno == ENOTDIR)
|
||||
key = __UNCONST(PW_POLICY_DEFAULTKEY);
|
||||
|
||||
break;
|
||||
|
||||
case PW_POLICY_BYPASSWD: {
|
||||
|
@ -330,16 +364,17 @@ pw_policy_test(char *pw, void *key, int how)
|
|||
* try a policy for the login class. If can't find any,
|
||||
* fallback to the default.
|
||||
*/
|
||||
errno = 0;
|
||||
PW_GETCONF(buf, sizeof(buf), pentry->pw_name, "foo");
|
||||
pw_getconf(buf, sizeof(buf), pentry->pw_name, "foo");
|
||||
if (errno == ENOTDIR) {
|
||||
PW_GETCONF(buf, sizeof(buf), pentry->pw_class, "foo");
|
||||
memset(buf, 0, sizeof(buf));
|
||||
pw_getconf(buf, sizeof(buf), pentry->pw_class, "foo");
|
||||
if (errno == ENOTDIR)
|
||||
key = __UNCONST(PW_POLICY_DEFAULTKEY);
|
||||
else
|
||||
key = pentry->pw_class;
|
||||
} else
|
||||
key = pentry->pw_name;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -350,12 +385,12 @@ pw_policy_test(char *pw, void *key, int how)
|
|||
* Check for policy for given group. If can't find any,
|
||||
* fallback to the default.
|
||||
*/
|
||||
errno = 0;
|
||||
PW_GETCONF(buf, sizeof(buf), gentry->gr_name, "foo");
|
||||
pw_getconf(buf, sizeof(buf), gentry->gr_name, "foo");
|
||||
if (errno == ENOTDIR)
|
||||
key = __UNCONST(PW_POLICY_DEFAULTKEY);
|
||||
else
|
||||
key = gentry->gr_name;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -367,13 +402,40 @@ pw_policy_test(char *pw, void *key, int how)
|
|||
return (EINVAL);
|
||||
}
|
||||
|
||||
test_policies:
|
||||
pwlen = strlen(pw);
|
||||
load_policies:
|
||||
hp = &handlers[0];
|
||||
while (hp->name != NULL) {
|
||||
int error;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
pw_getconf(buf, sizeof(buf), key, hp->name);
|
||||
if (*buf) {
|
||||
error = hp->handler(policy, LOAD_POLICY, NULL, buf,
|
||||
hp->arg2);
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
|
||||
hp++;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pw_policy_test(struct pw_policy *policy, char *pw)
|
||||
{
|
||||
struct pw_policy_handler *hp;
|
||||
|
||||
if (policy == NULL)
|
||||
return (0);
|
||||
|
||||
if (pw == NULL)
|
||||
return (EFAULT);
|
||||
|
||||
hp = &handlers[0];
|
||||
while (hp->name != NULL) {
|
||||
PW_GETCONF(buf, sizeof(buf), key, hp->name);
|
||||
if (*buf && hp->handler(pw, pwlen, buf, hp->arg2) != 0)
|
||||
if (hp->handler(policy, TEST_POLICY, pw, NULL, hp->arg2) != 0)
|
||||
return (EPERM);
|
||||
|
||||
hp++;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# $NetBSD: shlib_version,v 1.38 2005/12/20 21:32:20 christos Exp $
|
||||
# $NetBSD: shlib_version,v 1.39 2006/02/18 10:52:48 elad Exp $
|
||||
# Remember to update distrib/sets/lists/base/shl.* when changing
|
||||
#
|
||||
major=7
|
||||
minor=8
|
||||
minor=9
|
||||
|
|
Loading…
Reference in New Issue