mirror of
https://github.com/postgres/postgres.git
synced 2025-04-22 23:02:54 +03:00
Remove contrib/chkpass
The recent addition of a test suite for this module revealed a few problems. It uses a crypt() method that is no longer considered secure and doesn't work anymore on some platforms. Using a volatile input function violates internal sanity check assumptions and leads to failures on the build farm. So this module is neither a usable security tool nor a good example for an extension. No one wanted to argue for keeping or improving it, so remove it. Discussion: https://www.postgresql.org/message-id/5645b0d7-cc40-6ab5-c553-292a91091ee7%402ndquadrant.com
This commit is contained in:
parent
ed87e19807
commit
5d3cad5647
@ -12,7 +12,6 @@ SUBDIRS = \
|
||||
bloom \
|
||||
btree_gin \
|
||||
btree_gist \
|
||||
chkpass \
|
||||
citext \
|
||||
cube \
|
||||
dblink \
|
||||
|
4
contrib/chkpass/.gitignore
vendored
4
contrib/chkpass/.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
# Generated subdirectories
|
||||
/log/
|
||||
/results/
|
||||
/tmp_check/
|
@ -1,23 +0,0 @@
|
||||
# contrib/chkpass/Makefile
|
||||
|
||||
MODULE_big = chkpass
|
||||
OBJS = chkpass.o $(WIN32RES)
|
||||
|
||||
EXTENSION = chkpass
|
||||
DATA = chkpass--1.0.sql chkpass--unpackaged--1.0.sql
|
||||
PGFILEDESC = "chkpass - encrypted password data type"
|
||||
|
||||
SHLIB_LINK = $(filter -lcrypt, $(LIBS))
|
||||
|
||||
REGRESS = chkpass
|
||||
|
||||
ifdef USE_PGXS
|
||||
PG_CONFIG = pg_config
|
||||
PGXS := $(shell $(PG_CONFIG) --pgxs)
|
||||
include $(PGXS)
|
||||
else
|
||||
subdir = contrib/chkpass
|
||||
top_builddir = ../..
|
||||
include $(top_builddir)/src/Makefile.global
|
||||
include $(top_srcdir)/contrib/contrib-global.mk
|
||||
endif
|
@ -1,70 +0,0 @@
|
||||
/* contrib/chkpass/chkpass--1.0.sql */
|
||||
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "CREATE EXTENSION chkpass" to load this file. \quit
|
||||
|
||||
--
|
||||
-- Input and output functions and the type itself:
|
||||
--
|
||||
|
||||
CREATE FUNCTION chkpass_in(cstring)
|
||||
RETURNS chkpass
|
||||
AS 'MODULE_PATHNAME'
|
||||
LANGUAGE C STRICT VOLATILE;
|
||||
-- Note: chkpass_in actually is volatile, because of its use of random().
|
||||
-- In hindsight that was a bad idea, but there's no way to change it without
|
||||
-- breaking some usage patterns.
|
||||
|
||||
CREATE FUNCTION chkpass_out(chkpass)
|
||||
RETURNS cstring
|
||||
AS 'MODULE_PATHNAME'
|
||||
LANGUAGE C STRICT IMMUTABLE;
|
||||
|
||||
CREATE TYPE chkpass (
|
||||
internallength = 16,
|
||||
input = chkpass_in,
|
||||
output = chkpass_out
|
||||
);
|
||||
|
||||
CREATE FUNCTION raw(chkpass)
|
||||
RETURNS text
|
||||
AS 'MODULE_PATHNAME', 'chkpass_rout'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
--
|
||||
-- The various boolean tests:
|
||||
--
|
||||
|
||||
CREATE FUNCTION eq(chkpass, text)
|
||||
RETURNS bool
|
||||
AS 'MODULE_PATHNAME', 'chkpass_eq'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION ne(chkpass, text)
|
||||
RETURNS bool
|
||||
AS 'MODULE_PATHNAME', 'chkpass_ne'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
--
|
||||
-- Now the operators.
|
||||
--
|
||||
|
||||
CREATE OPERATOR = (
|
||||
leftarg = chkpass,
|
||||
rightarg = text,
|
||||
negator = <>,
|
||||
procedure = eq
|
||||
);
|
||||
|
||||
CREATE OPERATOR <> (
|
||||
leftarg = chkpass,
|
||||
rightarg = text,
|
||||
negator = =,
|
||||
procedure = ne
|
||||
);
|
||||
|
||||
COMMENT ON TYPE chkpass IS 'password type with checks';
|
||||
|
||||
--
|
||||
-- eof
|
||||
--
|
@ -1,13 +0,0 @@
|
||||
/* contrib/chkpass/chkpass--unpackaged--1.0.sql */
|
||||
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "CREATE EXTENSION chkpass FROM unpackaged" to load this file. \quit
|
||||
|
||||
ALTER EXTENSION chkpass ADD type chkpass;
|
||||
ALTER EXTENSION chkpass ADD function chkpass_in(cstring);
|
||||
ALTER EXTENSION chkpass ADD function chkpass_out(chkpass);
|
||||
ALTER EXTENSION chkpass ADD function raw(chkpass);
|
||||
ALTER EXTENSION chkpass ADD function eq(chkpass,text);
|
||||
ALTER EXTENSION chkpass ADD function ne(chkpass,text);
|
||||
ALTER EXTENSION chkpass ADD operator <>(chkpass,text);
|
||||
ALTER EXTENSION chkpass ADD operator =(chkpass,text);
|
@ -1,175 +0,0 @@
|
||||
/*
|
||||
* PostgreSQL type definitions for chkpass
|
||||
* Written by D'Arcy J.M. Cain
|
||||
* darcy@druid.net
|
||||
* http://www.druid.net/darcy/
|
||||
*
|
||||
* contrib/chkpass/chkpass.c
|
||||
* best viewed with tabs set to 4
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#ifdef HAVE_CRYPT_H
|
||||
#include <crypt.h>
|
||||
#endif
|
||||
|
||||
#include "fmgr.h"
|
||||
#include "utils/backend_random.h"
|
||||
#include "utils/builtins.h"
|
||||
|
||||
PG_MODULE_MAGIC;
|
||||
|
||||
/*
|
||||
* This type encrypts it's input unless the first character is a colon.
|
||||
* The output is the encrypted form with a leading colon. The output
|
||||
* format is designed to allow dump and reload operations to work as
|
||||
* expected without doing special tricks.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This is the internal storage format for CHKPASSs.
|
||||
* 15 is all I need but add a little buffer
|
||||
*/
|
||||
|
||||
typedef struct chkpass
|
||||
{
|
||||
char password[16];
|
||||
} chkpass;
|
||||
|
||||
|
||||
/* This function checks that the password is a good one
|
||||
* It's just a placeholder for now */
|
||||
static int
|
||||
verify_pass(const char *str)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* CHKPASS reader.
|
||||
*/
|
||||
PG_FUNCTION_INFO_V1(chkpass_in);
|
||||
Datum
|
||||
chkpass_in(PG_FUNCTION_ARGS)
|
||||
{
|
||||
char *str = PG_GETARG_CSTRING(0);
|
||||
chkpass *result;
|
||||
char mysalt[4];
|
||||
char *crypt_output;
|
||||
static char salt_chars[] =
|
||||
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
/* special case to let us enter encrypted passwords */
|
||||
if (*str == ':')
|
||||
{
|
||||
result = (chkpass *) palloc0(sizeof(chkpass));
|
||||
strlcpy(result->password, str + 1, 13 + 1);
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
if (verify_pass(str) != 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATA_EXCEPTION),
|
||||
errmsg("password \"%s\" is weak", str)));
|
||||
|
||||
result = (chkpass *) palloc0(sizeof(chkpass));
|
||||
|
||||
if (!pg_backend_random(mysalt, 2))
|
||||
ereport(ERROR,
|
||||
(errmsg("could not generate random salt")));
|
||||
|
||||
mysalt[0] = salt_chars[mysalt[0] & 0x3f];
|
||||
mysalt[1] = salt_chars[mysalt[1] & 0x3f];
|
||||
mysalt[2] = 0; /* technically the terminator is not necessary
|
||||
* but I like to play safe */
|
||||
|
||||
crypt_output = crypt(str, mysalt);
|
||||
if (crypt_output == NULL)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("crypt() failed")));
|
||||
|
||||
strlcpy(result->password, crypt_output, sizeof(result->password));
|
||||
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* CHKPASS output function.
|
||||
* Just like any string but we know it is max 15 (13 plus colon and terminator.)
|
||||
*/
|
||||
|
||||
PG_FUNCTION_INFO_V1(chkpass_out);
|
||||
Datum
|
||||
chkpass_out(PG_FUNCTION_ARGS)
|
||||
{
|
||||
chkpass *password = (chkpass *) PG_GETARG_POINTER(0);
|
||||
char *result;
|
||||
|
||||
result = (char *) palloc(16);
|
||||
result[0] = ':';
|
||||
strlcpy(result + 1, password->password, 15);
|
||||
|
||||
PG_RETURN_CSTRING(result);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* special output function that doesn't output the colon
|
||||
*/
|
||||
|
||||
PG_FUNCTION_INFO_V1(chkpass_rout);
|
||||
Datum
|
||||
chkpass_rout(PG_FUNCTION_ARGS)
|
||||
{
|
||||
chkpass *password = (chkpass *) PG_GETARG_POINTER(0);
|
||||
|
||||
PG_RETURN_TEXT_P(cstring_to_text(password->password));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Boolean tests
|
||||
*/
|
||||
|
||||
PG_FUNCTION_INFO_V1(chkpass_eq);
|
||||
Datum
|
||||
chkpass_eq(PG_FUNCTION_ARGS)
|
||||
{
|
||||
chkpass *a1 = (chkpass *) PG_GETARG_POINTER(0);
|
||||
text *a2 = PG_GETARG_TEXT_PP(1);
|
||||
char str[9];
|
||||
char *crypt_output;
|
||||
|
||||
text_to_cstring_buffer(a2, str, sizeof(str));
|
||||
crypt_output = crypt(str, a1->password);
|
||||
if (crypt_output == NULL)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("crypt() failed")));
|
||||
|
||||
PG_RETURN_BOOL(strcmp(a1->password, crypt_output) == 0);
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(chkpass_ne);
|
||||
Datum
|
||||
chkpass_ne(PG_FUNCTION_ARGS)
|
||||
{
|
||||
chkpass *a1 = (chkpass *) PG_GETARG_POINTER(0);
|
||||
text *a2 = PG_GETARG_TEXT_PP(1);
|
||||
char str[9];
|
||||
char *crypt_output;
|
||||
|
||||
text_to_cstring_buffer(a2, str, sizeof(str));
|
||||
crypt_output = crypt(str, a1->password);
|
||||
if (crypt_output == NULL)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("crypt() failed")));
|
||||
|
||||
PG_RETURN_BOOL(strcmp(a1->password, crypt_output) != 0);
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
# chkpass extension
|
||||
comment = 'data type for auto-encrypted passwords'
|
||||
default_version = '1.0'
|
||||
module_pathname = '$libdir/chkpass'
|
||||
relocatable = true
|
@ -1,18 +0,0 @@
|
||||
CREATE EXTENSION chkpass;
|
||||
WARNING: type input function chkpass_in should not be volatile
|
||||
CREATE TABLE test (i int, p chkpass);
|
||||
INSERT INTO test VALUES (1, 'hello'), (2, 'goodbye');
|
||||
SELECT i, p = 'hello' AS "hello?" FROM test;
|
||||
i | hello?
|
||||
---+--------
|
||||
1 | t
|
||||
2 | f
|
||||
(2 rows)
|
||||
|
||||
SELECT i, p <> 'hello' AS "!hello?" FROM test;
|
||||
i | !hello?
|
||||
---+---------
|
||||
1 | f
|
||||
2 | t
|
||||
(2 rows)
|
||||
|
@ -1,7 +0,0 @@
|
||||
CREATE EXTENSION chkpass;
|
||||
|
||||
CREATE TABLE test (i int, p chkpass);
|
||||
INSERT INTO test VALUES (1, 'hello'), (2, 'goodbye');
|
||||
|
||||
SELECT i, p = 'hello' AS "hello?" FROM test;
|
||||
SELECT i, p <> 'hello' AS "!hello?" FROM test;
|
@ -1,95 +0,0 @@
|
||||
<!-- doc/src/sgml/chkpass.sgml -->
|
||||
|
||||
<sect1 id="chkpass" xreflabel="chkpass">
|
||||
<title>chkpass</title>
|
||||
|
||||
<indexterm zone="chkpass">
|
||||
<primary>chkpass</primary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
This module implements a data type <type>chkpass</> that is
|
||||
designed for storing encrypted passwords.
|
||||
Each password is automatically converted to encrypted form upon entry,
|
||||
and is always stored encrypted. To compare, simply compare against a clear
|
||||
text password and the comparison function will encrypt it before comparing.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
There are provisions in the code to report an error if the password is
|
||||
determined to be easily crackable. However, this is currently just
|
||||
a stub that does nothing.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If you precede an input string with a colon, it is assumed to be an
|
||||
already-encrypted password, and is stored without further encryption.
|
||||
This allows entry of previously-encrypted passwords.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
On output, a colon is prepended. This makes it possible to dump and reload
|
||||
passwords without re-encrypting them. If you want the encrypted password
|
||||
without the colon then use the <function>raw()</> function.
|
||||
This allows you to use the
|
||||
type with things like Apache's <literal>Auth_PostgreSQL</> module.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The encryption uses the standard Unix function <function>crypt()</>,
|
||||
and so it suffers
|
||||
from all the usual limitations of that function; notably that only the
|
||||
first eight characters of a password are considered.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Note that the <type>chkpass</type> data type is not indexable.
|
||||
<!--
|
||||
I haven't worried about making this type indexable. I doubt that anyone
|
||||
would ever need to sort a file in order of encrypted password.
|
||||
-->
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Sample usage:
|
||||
</para>
|
||||
|
||||
<programlisting>
|
||||
test=# create table test (p chkpass);
|
||||
CREATE TABLE
|
||||
test=# insert into test values ('hello');
|
||||
INSERT 0 1
|
||||
test=# select * from test;
|
||||
p
|
||||
----------------
|
||||
:dVGkpXdOrE3ko
|
||||
(1 row)
|
||||
|
||||
test=# select raw(p) from test;
|
||||
raw
|
||||
---------------
|
||||
dVGkpXdOrE3ko
|
||||
(1 row)
|
||||
|
||||
test=# select p = 'hello' from test;
|
||||
?column?
|
||||
----------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
test=# select p = 'goodbye' from test;
|
||||
?column?
|
||||
----------
|
||||
f
|
||||
(1 row)
|
||||
</programlisting>
|
||||
|
||||
<sect2>
|
||||
<title>Author</title>
|
||||
|
||||
<para>
|
||||
D'Arcy J.M. Cain (<email>darcy@druid.net</email>)
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
@ -109,7 +109,6 @@ CREATE EXTENSION <replaceable>module_name</> FROM unpackaged;
|
||||
&bloom;
|
||||
&btree-gin;
|
||||
&btree-gist;
|
||||
&chkpass;
|
||||
&citext;
|
||||
&cube;
|
||||
&dblink;
|
||||
|
@ -110,7 +110,6 @@
|
||||
<!ENTITY bloom SYSTEM "bloom.sgml">
|
||||
<!ENTITY btree-gin SYSTEM "btree-gin.sgml">
|
||||
<!ENTITY btree-gist SYSTEM "btree-gist.sgml">
|
||||
<!ENTITY chkpass SYSTEM "chkpass.sgml">
|
||||
<!ENTITY citext SYSTEM "citext.sgml">
|
||||
<!ENTITY cube SYSTEM "cube.sgml">
|
||||
<!ENTITY dblink SYSTEM "dblink.sgml">
|
||||
|
Loading…
x
Reference in New Issue
Block a user