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