2001-05-03 20:32:13 +08:00
|
|
|
/*
|
|
|
|
* PostgreSQL type definitions for chkpass
|
|
|
|
* Written by D'Arcy J.M. Cain
|
|
|
|
* darcy@druid.net
|
|
|
|
* http://www.druid.net/darcy/
|
|
|
|
*
|
2007-02-28 07:48:10 +08:00
|
|
|
* $PostgreSQL: pgsql/contrib/chkpass/chkpass.c,v 1.19 2007/02/27 23:48:05 tgl Exp $
|
2001-05-03 20:32:13 +08:00
|
|
|
* best viewed with tabs set to 4
|
|
|
|
*/
|
|
|
|
|
2001-12-20 02:49:24 +08:00
|
|
|
#include "postgres.h"
|
|
|
|
|
2001-05-03 20:32:13 +08:00
|
|
|
#include <time.h>
|
|
|
|
#include <unistd.h>
|
2001-12-20 02:49:24 +08:00
|
|
|
#ifdef HAVE_CRYPT_H
|
|
|
|
#include <crypt.h>
|
|
|
|
#endif
|
2001-05-03 20:32:13 +08:00
|
|
|
|
2001-12-20 02:49:24 +08:00
|
|
|
#include "fmgr.h"
|
2001-05-03 20:32:13 +08:00
|
|
|
|
2006-05-31 06:12:16 +08:00
|
|
|
PG_MODULE_MAGIC;
|
|
|
|
|
2001-05-03 20:32:13 +08:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
{
|
2001-10-25 13:50:21 +08:00
|
|
|
char password[16];
|
2001-11-06 01:46:40 +08:00
|
|
|
} chkpass;
|
2001-05-03 20:32:13 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Various forward declarations:
|
|
|
|
*/
|
|
|
|
|
2001-05-28 23:34:27 +08:00
|
|
|
Datum chkpass_in(PG_FUNCTION_ARGS);
|
|
|
|
Datum chkpass_out(PG_FUNCTION_ARGS);
|
|
|
|
Datum chkpass_rout(PG_FUNCTION_ARGS);
|
2001-05-03 20:32:13 +08:00
|
|
|
|
|
|
|
/* Only equal or not equal make sense */
|
2001-05-28 23:34:27 +08:00
|
|
|
Datum chkpass_eq(PG_FUNCTION_ARGS);
|
|
|
|
Datum chkpass_ne(PG_FUNCTION_ARGS);
|
|
|
|
|
2001-05-03 20:32:13 +08:00
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
2002-10-26 23:01:01 +08:00
|
|
|
PG_FUNCTION_INFO_V1(chkpass_in);
|
2001-05-28 23:34:27 +08:00
|
|
|
Datum
|
|
|
|
chkpass_in(PG_FUNCTION_ARGS)
|
2001-05-03 20:32:13 +08:00
|
|
|
{
|
2001-10-25 13:50:21 +08:00
|
|
|
char *str = PG_GETARG_CSTRING(0);
|
|
|
|
chkpass *result;
|
2001-05-03 20:32:13 +08:00
|
|
|
char mysalt[4];
|
|
|
|
static char salt_chars[] =
|
2001-10-25 13:50:21 +08:00
|
|
|
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
2001-05-03 20:32:13 +08:00
|
|
|
|
|
|
|
/* special case to let us enter encrypted passwords */
|
|
|
|
if (*str == ':')
|
|
|
|
{
|
|
|
|
result = (chkpass *) palloc(sizeof(chkpass));
|
2007-02-07 08:52:35 +08:00
|
|
|
strlcpy(result->password, str + 1, 13 + 1);
|
2001-05-30 10:11:46 +08:00
|
|
|
PG_RETURN_POINTER(result);
|
2001-05-03 20:32:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (verify_pass(str) != 0)
|
2003-07-25 01:52:50 +08:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATA_EXCEPTION),
|
|
|
|
errmsg("password \"%s\" is weak", str)));
|
|
|
|
|
2001-05-03 20:32:13 +08:00
|
|
|
result = (chkpass *) palloc(sizeof(chkpass));
|
|
|
|
|
|
|
|
mysalt[0] = salt_chars[random() & 0x3f];
|
|
|
|
mysalt[1] = salt_chars[random() & 0x3f];
|
2005-10-15 10:49:52 +08:00
|
|
|
mysalt[2] = 0; /* technically the terminator is not necessary
|
|
|
|
* but I like to play safe */
|
2001-05-03 20:32:13 +08:00
|
|
|
strcpy(result->password, crypt(str, mysalt));
|
2001-05-30 10:11:46 +08:00
|
|
|
PG_RETURN_POINTER(result);
|
2001-05-03 20:32:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* CHKPASS output function.
|
|
|
|
* Just like any string but we know it is max 15 (13 plus colon and terminator.)
|
|
|
|
*/
|
|
|
|
|
2002-10-26 23:01:01 +08:00
|
|
|
PG_FUNCTION_INFO_V1(chkpass_out);
|
2001-05-28 23:34:27 +08:00
|
|
|
Datum
|
|
|
|
chkpass_out(PG_FUNCTION_ARGS)
|
2001-05-03 20:32:13 +08:00
|
|
|
{
|
2001-05-28 23:34:27 +08:00
|
|
|
chkpass *password = (chkpass *) PG_GETARG_POINTER(0);
|
2001-05-03 20:32:13 +08:00
|
|
|
char *result;
|
|
|
|
|
2006-03-20 06:22:56 +08:00
|
|
|
result = (char *) palloc(16);
|
|
|
|
result[0] = ':';
|
|
|
|
strcpy(result + 1, password->password);
|
2001-05-03 20:32:13 +08:00
|
|
|
|
2001-05-28 23:34:27 +08:00
|
|
|
PG_RETURN_CSTRING(result);
|
2001-05-03 20:32:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* special output function that doesn't output the colon
|
|
|
|
*/
|
|
|
|
|
2002-10-26 23:01:01 +08:00
|
|
|
PG_FUNCTION_INFO_V1(chkpass_rout);
|
2001-05-28 23:34:27 +08:00
|
|
|
Datum
|
|
|
|
chkpass_rout(PG_FUNCTION_ARGS)
|
2001-05-03 20:32:13 +08:00
|
|
|
{
|
2001-05-28 23:34:27 +08:00
|
|
|
chkpass *password = (chkpass *) PG_GETARG_POINTER(0);
|
2005-01-30 06:35:02 +08:00
|
|
|
text *result;
|
2007-02-28 07:48:10 +08:00
|
|
|
int slen;
|
2001-05-03 20:32:13 +08:00
|
|
|
|
2007-02-28 07:48:10 +08:00
|
|
|
slen = strlen(password->password);
|
|
|
|
result = (text *) palloc(VARHDRSZ + slen);
|
|
|
|
SET_VARSIZE(result, VARHDRSZ + slen);
|
|
|
|
memcpy(VARDATA(result), password->password, slen);
|
2001-05-03 20:32:13 +08:00
|
|
|
|
2002-08-29 20:18:20 +08:00
|
|
|
PG_RETURN_TEXT_P(result);
|
2001-05-03 20:32:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Boolean tests
|
|
|
|
*/
|
|
|
|
|
2002-10-26 23:01:01 +08:00
|
|
|
PG_FUNCTION_INFO_V1(chkpass_eq);
|
2001-05-28 23:34:27 +08:00
|
|
|
Datum
|
|
|
|
chkpass_eq(PG_FUNCTION_ARGS)
|
2001-05-03 20:32:13 +08:00
|
|
|
{
|
2001-05-28 23:34:27 +08:00
|
|
|
chkpass *a1 = (chkpass *) PG_GETARG_POINTER(0);
|
2001-10-25 13:50:21 +08:00
|
|
|
text *a2 = (text *) PG_GETARG_TEXT_P(1);
|
|
|
|
char str[10];
|
2007-02-28 07:48:10 +08:00
|
|
|
int sz;
|
2001-05-28 23:34:27 +08:00
|
|
|
|
2007-02-28 07:48:10 +08:00
|
|
|
sz = Min(VARSIZE(a2) - VARHDRSZ, 8);
|
|
|
|
memcpy(str, VARDATA(a2), sz);
|
|
|
|
str[sz] = '\0';
|
2001-10-25 13:50:21 +08:00
|
|
|
PG_RETURN_BOOL(strcmp(a1->password, crypt(str, a1->password)) == 0);
|
2001-05-03 20:32:13 +08:00
|
|
|
}
|
|
|
|
|
2002-10-26 23:01:01 +08:00
|
|
|
PG_FUNCTION_INFO_V1(chkpass_ne);
|
2001-05-28 23:34:27 +08:00
|
|
|
Datum
|
|
|
|
chkpass_ne(PG_FUNCTION_ARGS)
|
2001-05-03 20:32:13 +08:00
|
|
|
{
|
2001-05-28 23:34:27 +08:00
|
|
|
chkpass *a1 = (chkpass *) PG_GETARG_POINTER(0);
|
2001-10-25 13:50:21 +08:00
|
|
|
text *a2 = (text *) PG_GETARG_TEXT_P(1);
|
|
|
|
char str[10];
|
2007-02-28 07:48:10 +08:00
|
|
|
int sz;
|
2001-05-03 20:32:13 +08:00
|
|
|
|
2007-02-28 07:48:10 +08:00
|
|
|
sz = Min(VARSIZE(a2) - VARHDRSZ, 8);
|
|
|
|
memcpy(str, VARDATA(a2), sz);
|
|
|
|
str[sz] = '\0';
|
2001-10-25 13:50:21 +08:00
|
|
|
PG_RETURN_BOOL(strcmp(a1->password, crypt(str, a1->password)) != 0);
|
2001-05-03 20:32:13 +08:00
|
|
|
}
|