Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitc742b79

Browse files
committed
Add a hook to CREATE/ALTER ROLE to allow an external module to check the
strength of database passwords, and create a sample implementation ofsuch a hook as a new contrib module "passwordcheck".Laurenz Albe, reviewed by Takahiro Itagaki
1 parent5e66a51 commitc742b79

File tree

9 files changed

+313
-23
lines changed

9 files changed

+313
-23
lines changed

‎contrib/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# $PostgreSQL: pgsql/contrib/Makefile,v 1.89 2009/08/1810:34:39 teodor Exp $
1+
# $PostgreSQL: pgsql/contrib/Makefile,v 1.90 2009/11/1821:57:56 tgl Exp $
22

33
subdir = contrib
44
top_builddir = ..
@@ -25,6 +25,7 @@ SUBDIRS = \
2525
ltree\
2626
oid2name\
2727
pageinspect\
28+
passwordcheck\
2829
pg_buffercache\
2930
pg_freespacemap\
3031
pg_standby\

‎contrib/README

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ pageinspect -
104104
Allows inspection of database pages
105105
Heikki Linnakangas <heikki@enterprisedb.com>
106106

107+
passwordcheck -
108+
Simple password strength checker
109+
Laurenz Albe <laurenz.albe@wien.gv.at>
110+
107111
pg_buffercache -
108112
Real time queries on the shared buffer cache
109113
by Mark Kirkwood <markir@paradise.net.nz>

‎contrib/passwordcheck/Makefile

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# $PostgreSQL: pgsql/contrib/passwordcheck/Makefile,v 1.1 2009/11/18 21:57:56 tgl Exp $
2+
3+
MODULE_big = passwordcheck
4+
OBJS = passwordcheck.o
5+
6+
# uncomment the following two lines to enable cracklib support
7+
# PG_CPPFLAGS = -DUSE_CRACKLIB '-DCRACKLIB_DICTPATH="/usr/lib/cracklib_dict"'
8+
# SHLIB_LINK = -lcrack
9+
10+
ifdefUSE_PGXS
11+
PG_CONFIG = pg_config
12+
PGXS :=$(shell$(PG_CONFIG) --pgxs)
13+
include$(PGXS)
14+
else
15+
subdir = contrib/passwordcheck
16+
top_builddir = ../..
17+
include$(top_builddir)/src/Makefile.global
18+
include$(top_srcdir)/contrib/contrib-global.mk
19+
endif

‎contrib/passwordcheck/passwordcheck.c

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
/*-------------------------------------------------------------------------
2+
*
3+
* passwordcheck.c
4+
*
5+
*
6+
* Copyright (c) 2009, PostgreSQL Global Development Group
7+
*
8+
* Author: Laurenz Albe <laurenz.albe@wien.gv.at>
9+
*
10+
* IDENTIFICATION
11+
* $PostgreSQL: pgsql/contrib/passwordcheck/passwordcheck.c,v 1.1 2009/11/18 21:57:56 tgl Exp $
12+
*
13+
*-------------------------------------------------------------------------
14+
*/
15+
#include"postgres.h"
16+
17+
#include<ctype.h>
18+
19+
#ifdefUSE_CRACKLIB
20+
#include<crack.h>
21+
#endif
22+
23+
#include"commands/user.h"
24+
#include"fmgr.h"
25+
#include"libpq/md5.h"
26+
27+
28+
PG_MODULE_MAGIC;
29+
30+
/* passwords shorter than this will be rejected */
31+
#defineMIN_PWD_LENGTH 8
32+
33+
externvoid_PG_init(void);
34+
35+
/*
36+
* check_password
37+
*
38+
* performs checks on an encrypted or unencrypted password
39+
* ereport's if not acceptable
40+
*
41+
* username: name of role being created or changed
42+
* password: new password (possibly already encrypted)
43+
* password_type: PASSWORD_TYPE_PLAINTEXT or PASSWORD_TYPE_MD5 (there
44+
*could be other encryption schemes in future)
45+
* validuntil_time: password expiration time, as a timestamptz Datum
46+
* validuntil_null: true if password expiration time is NULL
47+
*
48+
* This sample implementation doesn't pay any attention to the password
49+
* expiration time, but you might wish to insist that it be non-null and
50+
* not too far in the future.
51+
*/
52+
staticvoid
53+
check_password(constchar*username,
54+
constchar*password,
55+
intpassword_type,
56+
Datumvaliduntil_time,
57+
boolvaliduntil_null)
58+
{
59+
intnamelen=strlen(username);
60+
intpwdlen=strlen(password);
61+
charencrypted[MD5_PASSWD_LEN+1];
62+
inti;
63+
boolpwd_has_letter,
64+
pwd_has_nonletter;
65+
66+
switch (password_type)
67+
{
68+
casePASSWORD_TYPE_MD5:
69+
/*
70+
* Unfortunately we cannot perform exhaustive checks on
71+
* encrypted passwords - we are restricted to guessing.
72+
* (Alternatively, we could insist on the password being
73+
* presented non-encrypted, but that has its own security
74+
* disadvantages.)
75+
*
76+
* We only check for username = password.
77+
*/
78+
if (!pg_md5_encrypt(username,username,namelen,encrypted))
79+
elog(ERROR,"password encryption failed");
80+
if (strcmp(password,encrypted)==0)
81+
ereport(ERROR,
82+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
83+
errmsg("password must not contain user name")));
84+
break;
85+
86+
casePASSWORD_TYPE_PLAINTEXT:
87+
/*
88+
* For unencrypted passwords we can perform better checks
89+
*/
90+
91+
/* enforce minimum length */
92+
if (pwdlen<MIN_PWD_LENGTH)
93+
ereport(ERROR,
94+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
95+
errmsg("password is too short")));
96+
97+
/* check if the password contains the username */
98+
if (strstr(password,username))
99+
ereport(ERROR,
100+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
101+
errmsg("password must not contain user name")));
102+
103+
/* check if the password contains both letters and non-letters */
104+
pwd_has_letter= false;
105+
pwd_has_nonletter= false;
106+
for (i=0;i<pwdlen;i++)
107+
{
108+
/*
109+
* isalpha() does not work for multibyte encodings
110+
* but let's consider non-ASCII characters non-letters
111+
*/
112+
if (isalpha((unsignedchar)password[i]))
113+
pwd_has_letter= true;
114+
else
115+
pwd_has_nonletter= true;
116+
}
117+
if (!pwd_has_letter|| !pwd_has_nonletter)
118+
ereport(ERROR,
119+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
120+
errmsg("password must contain both letters and nonletters")));
121+
122+
#ifdefUSE_CRACKLIB
123+
/* call cracklib to check password */
124+
if (FascistCheck(password,CRACKLIB_DICTPATH))
125+
ereport(ERROR,
126+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
127+
errmsg("password is easily cracked")));
128+
#endif
129+
break;
130+
131+
default:
132+
elog(ERROR,"unrecognized password type: %d",password_type);
133+
break;
134+
}
135+
136+
/* all checks passed, password is ok */
137+
}
138+
139+
/*
140+
* Module initialization function
141+
*/
142+
void
143+
_PG_init(void)
144+
{
145+
/* activate password checks when the module is loaded */
146+
check_password_hook=check_password;
147+
}

‎doc/src/sgml/contrib.sgml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/contrib.sgml,v 1.14 2009/08/1810:34:39 teodor Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/contrib.sgml,v 1.15 2009/11/1821:57:56 tgl Exp $ -->
22

33
<appendix id="contrib">
44
<title>Additional Supplied Modules</title>
@@ -98,6 +98,7 @@ psql -d dbname -f <replaceable>SHAREDIR</>/contrib/<replaceable>module</>.sql
9898
&ltree;
9999
&oid2name;
100100
&pageinspect;
101+
&passwordcheck;
101102
&pgbench;
102103
&pgbuffercache;
103104
&pgcrypto;

‎doc/src/sgml/filelist.sgml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/filelist.sgml,v 1.64 2009/08/1810:34:39 teodor Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/filelist.sgml,v 1.65 2009/11/1821:57:56 tgl Exp $ -->
22

33
<!entity history SYSTEM "history.sgml">
44
<!entity info SYSTEM "info.sgml">
@@ -111,6 +111,7 @@
111111
<!entity ltree SYSTEM "ltree.sgml">
112112
<!entity oid2name SYSTEM "oid2name.sgml">
113113
<!entity pageinspect SYSTEM "pageinspect.sgml">
114+
<!entity passwordcheck SYSTEM "passwordcheck.sgml">
114115
<!entity pgbench SYSTEM "pgbench.sgml">
115116
<!entity pgbuffercache SYSTEM "pgbuffercache.sgml">
116117
<!entity pgcrypto SYSTEM "pgcrypto.sgml">

‎doc/src/sgml/passwordcheck.sgml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/passwordcheck.sgml,v 1.1 2009/11/18 21:57:56 tgl Exp $ -->
2+
3+
<sect1 id="passwordcheck">
4+
<title>passwordcheck</title>
5+
6+
<indexterm zone="passwordcheck">
7+
<primary>passwordcheck</primary>
8+
</indexterm>
9+
10+
<para>
11+
The <filename>passwordcheck</filename> module checks users' passwords
12+
whenever they are set with
13+
<xref linkend="SQL-CREATEROLE" endterm="SQL-CREATEROLE-title"> or
14+
<xref linkend="SQL-ALTERROLE" endterm="SQL-ALTERROLE-title">.
15+
If a password is considered too weak, it will be rejected and
16+
the command will terminate with an error.
17+
</para>
18+
19+
<para>
20+
To enable this module, add <literal>'$libdir/passwordcheck'</literal>
21+
to <xref linkend="guc-shared-preload-libraries"> in
22+
<filename>postgresql.conf</filename>, then restart the server.
23+
</para>
24+
25+
<para>
26+
You can adapt this module to your needs by changing the source code.
27+
For example, you can use
28+
<ulink url="http://sourceforge.net/projects/cracklib/">CrackLib</ulink>
29+
to check passwords &mdash; this only requires uncommenting
30+
two lines in the <filename>Makefile</filename> and rebuilding the
31+
module. (We cannot include <productname>CrackLib</productname>
32+
by default for license reasons.)
33+
Without <productname>CrackLib</productname>, the module enforces a few
34+
simple rules for password strength, which you can modify or extend
35+
as you see fit.
36+
</para>
37+
38+
<caution>
39+
<para>
40+
To prevent unencrypted passwords from being sent across the network,
41+
written to the server log or otherwise stolen by a database administrator,
42+
<productname>PostgreSQL</productname> allows the user to supply
43+
pre-encrypted passwords. Many client programs make use of this
44+
functionality and encrypt the password before sending it to the server.
45+
</para>
46+
<para>
47+
This limits the usefulness of the <filename>passwordcheck</filename>
48+
module, because in that case it can only try to guess the password.
49+
For this reason, <filename>passwordcheck</filename> is not
50+
recommendable if your security requirements are high.
51+
It is more secure to use an external authentication method such as Kerberos
52+
(see <xref linkend="client-authentication">) than to rely on
53+
passwords within the database.
54+
</para>
55+
<para>
56+
Alternatively, you could modify <filename>passwordcheck</filename>
57+
to reject pre-encrypted passwords, but forcing users to set their
58+
passwords in clear text carries its own security risks.
59+
</para>
60+
</caution>
61+
62+
</sect1>

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp