mirror of https://github.com/postgres/postgres
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.compull/31/head^2
parent
ed87e19807
commit
5d3cad5647
@ -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> |
|
Loading…
Reference in new issue