Add a hook to CREATE/ALTER ROLE to allow an external module to check the
strength of database passwords, and create a sample implementation of such a hook as a new contrib module "passwordcheck". Laurenz Albe, reviewed by Takahiro Itagaki
This commit is contained in:
parent
5e66a51c2e
commit
c742b795dd
@ -1,4 +1,4 @@
|
|||||||
# $PostgreSQL: pgsql/contrib/Makefile,v 1.89 2009/08/18 10:34:39 teodor Exp $
|
# $PostgreSQL: pgsql/contrib/Makefile,v 1.90 2009/11/18 21:57:56 tgl Exp $
|
||||||
|
|
||||||
subdir = contrib
|
subdir = contrib
|
||||||
top_builddir = ..
|
top_builddir = ..
|
||||||
@ -25,6 +25,7 @@ SUBDIRS = \
|
|||||||
ltree \
|
ltree \
|
||||||
oid2name \
|
oid2name \
|
||||||
pageinspect \
|
pageinspect \
|
||||||
|
passwordcheck \
|
||||||
pg_buffercache \
|
pg_buffercache \
|
||||||
pg_freespacemap \
|
pg_freespacemap \
|
||||||
pg_standby \
|
pg_standby \
|
||||||
|
@ -104,6 +104,10 @@ pageinspect -
|
|||||||
Allows inspection of database pages
|
Allows inspection of database pages
|
||||||
Heikki Linnakangas <heikki@enterprisedb.com>
|
Heikki Linnakangas <heikki@enterprisedb.com>
|
||||||
|
|
||||||
|
passwordcheck -
|
||||||
|
Simple password strength checker
|
||||||
|
Laurenz Albe <laurenz.albe@wien.gv.at>
|
||||||
|
|
||||||
pg_buffercache -
|
pg_buffercache -
|
||||||
Real time queries on the shared buffer cache
|
Real time queries on the shared buffer cache
|
||||||
by Mark Kirkwood <markir@paradise.net.nz>
|
by Mark Kirkwood <markir@paradise.net.nz>
|
||||||
|
19
contrib/passwordcheck/Makefile
Normal file
19
contrib/passwordcheck/Makefile
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# $PostgreSQL: pgsql/contrib/passwordcheck/Makefile,v 1.1 2009/11/18 21:57:56 tgl Exp $
|
||||||
|
|
||||||
|
MODULE_big = passwordcheck
|
||||||
|
OBJS = passwordcheck.o
|
||||||
|
|
||||||
|
# uncomment the following two lines to enable cracklib support
|
||||||
|
# PG_CPPFLAGS = -DUSE_CRACKLIB '-DCRACKLIB_DICTPATH="/usr/lib/cracklib_dict"'
|
||||||
|
# SHLIB_LINK = -lcrack
|
||||||
|
|
||||||
|
ifdef USE_PGXS
|
||||||
|
PG_CONFIG = pg_config
|
||||||
|
PGXS := $(shell $(PG_CONFIG) --pgxs)
|
||||||
|
include $(PGXS)
|
||||||
|
else
|
||||||
|
subdir = contrib/passwordcheck
|
||||||
|
top_builddir = ../..
|
||||||
|
include $(top_builddir)/src/Makefile.global
|
||||||
|
include $(top_srcdir)/contrib/contrib-global.mk
|
||||||
|
endif
|
147
contrib/passwordcheck/passwordcheck.c
Normal file
147
contrib/passwordcheck/passwordcheck.c
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* passwordcheck.c
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009, PostgreSQL Global Development Group
|
||||||
|
*
|
||||||
|
* Author: Laurenz Albe <laurenz.albe@wien.gv.at>
|
||||||
|
*
|
||||||
|
* IDENTIFICATION
|
||||||
|
* $PostgreSQL: pgsql/contrib/passwordcheck/passwordcheck.c,v 1.1 2009/11/18 21:57:56 tgl Exp $
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#ifdef USE_CRACKLIB
|
||||||
|
#include <crack.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "commands/user.h"
|
||||||
|
#include "fmgr.h"
|
||||||
|
#include "libpq/md5.h"
|
||||||
|
|
||||||
|
|
||||||
|
PG_MODULE_MAGIC;
|
||||||
|
|
||||||
|
/* passwords shorter than this will be rejected */
|
||||||
|
#define MIN_PWD_LENGTH 8
|
||||||
|
|
||||||
|
extern void _PG_init(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check_password
|
||||||
|
*
|
||||||
|
* performs checks on an encrypted or unencrypted password
|
||||||
|
* ereport's if not acceptable
|
||||||
|
*
|
||||||
|
* username: name of role being created or changed
|
||||||
|
* password: new password (possibly already encrypted)
|
||||||
|
* password_type: PASSWORD_TYPE_PLAINTEXT or PASSWORD_TYPE_MD5 (there
|
||||||
|
* could be other encryption schemes in future)
|
||||||
|
* validuntil_time: password expiration time, as a timestamptz Datum
|
||||||
|
* validuntil_null: true if password expiration time is NULL
|
||||||
|
*
|
||||||
|
* This sample implementation doesn't pay any attention to the password
|
||||||
|
* expiration time, but you might wish to insist that it be non-null and
|
||||||
|
* not too far in the future.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
check_password(const char *username,
|
||||||
|
const char *password,
|
||||||
|
int password_type,
|
||||||
|
Datum validuntil_time,
|
||||||
|
bool validuntil_null)
|
||||||
|
{
|
||||||
|
int namelen = strlen(username);
|
||||||
|
int pwdlen = strlen(password);
|
||||||
|
char encrypted[MD5_PASSWD_LEN + 1];
|
||||||
|
int i;
|
||||||
|
bool pwd_has_letter,
|
||||||
|
pwd_has_nonletter;
|
||||||
|
|
||||||
|
switch (password_type)
|
||||||
|
{
|
||||||
|
case PASSWORD_TYPE_MD5:
|
||||||
|
/*
|
||||||
|
* Unfortunately we cannot perform exhaustive checks on
|
||||||
|
* encrypted passwords - we are restricted to guessing.
|
||||||
|
* (Alternatively, we could insist on the password being
|
||||||
|
* presented non-encrypted, but that has its own security
|
||||||
|
* disadvantages.)
|
||||||
|
*
|
||||||
|
* We only check for username = password.
|
||||||
|
*/
|
||||||
|
if (!pg_md5_encrypt(username, username, namelen, encrypted))
|
||||||
|
elog(ERROR, "password encryption failed");
|
||||||
|
if (strcmp(password, encrypted) == 0)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
|
errmsg("password must not contain user name")));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PASSWORD_TYPE_PLAINTEXT:
|
||||||
|
/*
|
||||||
|
* For unencrypted passwords we can perform better checks
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* enforce minimum length */
|
||||||
|
if (pwdlen < MIN_PWD_LENGTH)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
|
errmsg("password is too short")));
|
||||||
|
|
||||||
|
/* check if the password contains the username */
|
||||||
|
if (strstr(password, username))
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
|
errmsg("password must not contain user name")));
|
||||||
|
|
||||||
|
/* check if the password contains both letters and non-letters */
|
||||||
|
pwd_has_letter = false;
|
||||||
|
pwd_has_nonletter = false;
|
||||||
|
for (i = 0; i < pwdlen; i++)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* isalpha() does not work for multibyte encodings
|
||||||
|
* but let's consider non-ASCII characters non-letters
|
||||||
|
*/
|
||||||
|
if (isalpha((unsigned char) password[i]))
|
||||||
|
pwd_has_letter = true;
|
||||||
|
else
|
||||||
|
pwd_has_nonletter = true;
|
||||||
|
}
|
||||||
|
if (!pwd_has_letter || !pwd_has_nonletter)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
|
errmsg("password must contain both letters and nonletters")));
|
||||||
|
|
||||||
|
#ifdef USE_CRACKLIB
|
||||||
|
/* call cracklib to check password */
|
||||||
|
if (FascistCheck(password, CRACKLIB_DICTPATH))
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
|
errmsg("password is easily cracked")));
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
elog(ERROR, "unrecognized password type: %d", password_type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* all checks passed, password is ok */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Module initialization function
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
_PG_init(void)
|
||||||
|
{
|
||||||
|
/* activate password checks when the module is loaded */
|
||||||
|
check_password_hook = check_password;
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/contrib.sgml,v 1.14 2009/08/18 10:34:39 teodor Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/contrib.sgml,v 1.15 2009/11/18 21:57:56 tgl Exp $ -->
|
||||||
|
|
||||||
<appendix id="contrib">
|
<appendix id="contrib">
|
||||||
<title>Additional Supplied Modules</title>
|
<title>Additional Supplied Modules</title>
|
||||||
@ -98,6 +98,7 @@ psql -d dbname -f <replaceable>SHAREDIR</>/contrib/<replaceable>module</>.sql
|
|||||||
<ree;
|
<ree;
|
||||||
&oid2name;
|
&oid2name;
|
||||||
&pageinspect;
|
&pageinspect;
|
||||||
|
&passwordcheck;
|
||||||
&pgbench;
|
&pgbench;
|
||||||
&pgbuffercache;
|
&pgbuffercache;
|
||||||
&pgcrypto;
|
&pgcrypto;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/filelist.sgml,v 1.64 2009/08/18 10:34:39 teodor Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/filelist.sgml,v 1.65 2009/11/18 21:57:56 tgl Exp $ -->
|
||||||
|
|
||||||
<!entity history SYSTEM "history.sgml">
|
<!entity history SYSTEM "history.sgml">
|
||||||
<!entity info SYSTEM "info.sgml">
|
<!entity info SYSTEM "info.sgml">
|
||||||
@ -111,6 +111,7 @@
|
|||||||
<!entity ltree SYSTEM "ltree.sgml">
|
<!entity ltree SYSTEM "ltree.sgml">
|
||||||
<!entity oid2name SYSTEM "oid2name.sgml">
|
<!entity oid2name SYSTEM "oid2name.sgml">
|
||||||
<!entity pageinspect SYSTEM "pageinspect.sgml">
|
<!entity pageinspect SYSTEM "pageinspect.sgml">
|
||||||
|
<!entity passwordcheck SYSTEM "passwordcheck.sgml">
|
||||||
<!entity pgbench SYSTEM "pgbench.sgml">
|
<!entity pgbench SYSTEM "pgbench.sgml">
|
||||||
<!entity pgbuffercache SYSTEM "pgbuffercache.sgml">
|
<!entity pgbuffercache SYSTEM "pgbuffercache.sgml">
|
||||||
<!entity pgcrypto SYSTEM "pgcrypto.sgml">
|
<!entity pgcrypto SYSTEM "pgcrypto.sgml">
|
||||||
|
62
doc/src/sgml/passwordcheck.sgml
Normal file
62
doc/src/sgml/passwordcheck.sgml
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/passwordcheck.sgml,v 1.1 2009/11/18 21:57:56 tgl Exp $ -->
|
||||||
|
|
||||||
|
<sect1 id="passwordcheck">
|
||||||
|
<title>passwordcheck</title>
|
||||||
|
|
||||||
|
<indexterm zone="passwordcheck">
|
||||||
|
<primary>passwordcheck</primary>
|
||||||
|
</indexterm>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The <filename>passwordcheck</filename> module checks users' passwords
|
||||||
|
whenever they are set with
|
||||||
|
<xref linkend="SQL-CREATEROLE" endterm="SQL-CREATEROLE-title"> or
|
||||||
|
<xref linkend="SQL-ALTERROLE" endterm="SQL-ALTERROLE-title">.
|
||||||
|
If a password is considered too weak, it will be rejected and
|
||||||
|
the command will terminate with an error.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
To enable this module, add <literal>'$libdir/passwordcheck'</literal>
|
||||||
|
to <xref linkend="guc-shared-preload-libraries"> in
|
||||||
|
<filename>postgresql.conf</filename>, then restart the server.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
You can adapt this module to your needs by changing the source code.
|
||||||
|
For example, you can use
|
||||||
|
<ulink url="http://sourceforge.net/projects/cracklib/">CrackLib</ulink>
|
||||||
|
to check passwords — this only requires uncommenting
|
||||||
|
two lines in the <filename>Makefile</filename> and rebuilding the
|
||||||
|
module. (We cannot include <productname>CrackLib</productname>
|
||||||
|
by default for license reasons.)
|
||||||
|
Without <productname>CrackLib</productname>, the module enforces a few
|
||||||
|
simple rules for password strength, which you can modify or extend
|
||||||
|
as you see fit.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<caution>
|
||||||
|
<para>
|
||||||
|
To prevent unencrypted passwords from being sent across the network,
|
||||||
|
written to the server log or otherwise stolen by a database administrator,
|
||||||
|
<productname>PostgreSQL</productname> allows the user to supply
|
||||||
|
pre-encrypted passwords. Many client programs make use of this
|
||||||
|
functionality and encrypt the password before sending it to the server.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
This limits the usefulness of the <filename>passwordcheck</filename>
|
||||||
|
module, because in that case it can only try to guess the password.
|
||||||
|
For this reason, <filename>passwordcheck</filename> is not
|
||||||
|
recommendable if your security requirements are high.
|
||||||
|
It is more secure to use an external authentication method such as Kerberos
|
||||||
|
(see <xref linkend="client-authentication">) than to rely on
|
||||||
|
passwords within the database.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Alternatively, you could modify <filename>passwordcheck</filename>
|
||||||
|
to reject pre-encrypted passwords, but forcing users to set their
|
||||||
|
passwords in clear text carries its own security risks.
|
||||||
|
</para>
|
||||||
|
</caution>
|
||||||
|
|
||||||
|
</sect1>
|
@ -6,7 +6,7 @@
|
|||||||
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.189 2009/10/07 22:14:19 alvherre Exp $
|
* $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.190 2009/11/18 21:57:56 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -35,8 +35,12 @@
|
|||||||
#include "utils/tqual.h"
|
#include "utils/tqual.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* GUC parameter */
|
||||||
extern bool Password_encryption;
|
extern bool Password_encryption;
|
||||||
|
|
||||||
|
/* Hook to check passwords in CreateRole() and AlterRole() */
|
||||||
|
check_password_hook_type check_password_hook = NULL;
|
||||||
|
|
||||||
static List *roleNamesToIds(List *memberNames);
|
static List *roleNamesToIds(List *memberNames);
|
||||||
static void AddRoleMems(const char *rolename, Oid roleid,
|
static void AddRoleMems(const char *rolename, Oid roleid,
|
||||||
List *memberNames, List *memberIds,
|
List *memberNames, List *memberIds,
|
||||||
@ -96,6 +100,8 @@ CreateRole(CreateRoleStmt *stmt)
|
|||||||
List *rolemembers = NIL; /* roles to be members of this role */
|
List *rolemembers = NIL; /* roles to be members of this role */
|
||||||
List *adminmembers = NIL; /* roles to be admins of this role */
|
List *adminmembers = NIL; /* roles to be admins of this role */
|
||||||
char *validUntil = NULL; /* time the login is valid until */
|
char *validUntil = NULL; /* time the login is valid until */
|
||||||
|
Datum validUntil_datum; /* same, as timestamptz Datum */
|
||||||
|
bool validUntil_null;
|
||||||
DefElem *dpassword = NULL;
|
DefElem *dpassword = NULL;
|
||||||
DefElem *dissuper = NULL;
|
DefElem *dissuper = NULL;
|
||||||
DefElem *dinherit = NULL;
|
DefElem *dinherit = NULL;
|
||||||
@ -298,6 +304,31 @@ CreateRole(CreateRoleStmt *stmt)
|
|||||||
errmsg("role \"%s\" already exists",
|
errmsg("role \"%s\" already exists",
|
||||||
stmt->role)));
|
stmt->role)));
|
||||||
|
|
||||||
|
/* Convert validuntil to internal form */
|
||||||
|
if (validUntil)
|
||||||
|
{
|
||||||
|
validUntil_datum = DirectFunctionCall3(timestamptz_in,
|
||||||
|
CStringGetDatum(validUntil),
|
||||||
|
ObjectIdGetDatum(InvalidOid),
|
||||||
|
Int32GetDatum(-1));
|
||||||
|
validUntil_null = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
validUntil_datum = (Datum) 0;
|
||||||
|
validUntil_null = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call the password checking hook if there is one defined
|
||||||
|
*/
|
||||||
|
if (check_password_hook && password)
|
||||||
|
(*check_password_hook) (stmt->role,
|
||||||
|
password,
|
||||||
|
isMD5(password) ? PASSWORD_TYPE_MD5 : PASSWORD_TYPE_PLAINTEXT,
|
||||||
|
validUntil_datum,
|
||||||
|
validUntil_null);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Build a tuple to insert
|
* Build a tuple to insert
|
||||||
*/
|
*/
|
||||||
@ -333,15 +364,8 @@ CreateRole(CreateRoleStmt *stmt)
|
|||||||
else
|
else
|
||||||
new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
|
new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
|
||||||
|
|
||||||
if (validUntil)
|
new_record[Anum_pg_authid_rolvaliduntil - 1] = validUntil_datum;
|
||||||
new_record[Anum_pg_authid_rolvaliduntil - 1] =
|
new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null;
|
||||||
DirectFunctionCall3(timestamptz_in,
|
|
||||||
CStringGetDatum(validUntil),
|
|
||||||
ObjectIdGetDatum(InvalidOid),
|
|
||||||
Int32GetDatum(-1));
|
|
||||||
|
|
||||||
else
|
|
||||||
new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = true;
|
|
||||||
|
|
||||||
tuple = heap_form_tuple(pg_authid_dsc, new_record, new_record_nulls);
|
tuple = heap_form_tuple(pg_authid_dsc, new_record, new_record_nulls);
|
||||||
|
|
||||||
@ -419,6 +443,8 @@ AlterRole(AlterRoleStmt *stmt)
|
|||||||
int connlimit = -1; /* maximum connections allowed */
|
int connlimit = -1; /* maximum connections allowed */
|
||||||
List *rolemembers = NIL; /* roles to be added/removed */
|
List *rolemembers = NIL; /* roles to be added/removed */
|
||||||
char *validUntil = NULL; /* time the login is valid until */
|
char *validUntil = NULL; /* time the login is valid until */
|
||||||
|
Datum validUntil_datum; /* same, as timestamptz Datum */
|
||||||
|
bool validUntil_null;
|
||||||
DefElem *dpassword = NULL;
|
DefElem *dpassword = NULL;
|
||||||
DefElem *dissuper = NULL;
|
DefElem *dissuper = NULL;
|
||||||
DefElem *dinherit = NULL;
|
DefElem *dinherit = NULL;
|
||||||
@ -587,6 +613,33 @@ AlterRole(AlterRoleStmt *stmt)
|
|||||||
errmsg("permission denied")));
|
errmsg("permission denied")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Convert validuntil to internal form */
|
||||||
|
if (validUntil)
|
||||||
|
{
|
||||||
|
validUntil_datum = DirectFunctionCall3(timestamptz_in,
|
||||||
|
CStringGetDatum(validUntil),
|
||||||
|
ObjectIdGetDatum(InvalidOid),
|
||||||
|
Int32GetDatum(-1));
|
||||||
|
validUntil_null = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* fetch existing setting in case hook needs it */
|
||||||
|
validUntil_datum = SysCacheGetAttr(AUTHNAME, tuple,
|
||||||
|
Anum_pg_authid_rolvaliduntil,
|
||||||
|
&validUntil_null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call the password checking hook if there is one defined
|
||||||
|
*/
|
||||||
|
if (check_password_hook && password)
|
||||||
|
(*check_password_hook) (stmt->role,
|
||||||
|
password,
|
||||||
|
isMD5(password) ? PASSWORD_TYPE_MD5 : PASSWORD_TYPE_PLAINTEXT,
|
||||||
|
validUntil_datum,
|
||||||
|
validUntil_null);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Build an updated tuple, perusing the information just obtained
|
* Build an updated tuple, perusing the information just obtained
|
||||||
*/
|
*/
|
||||||
@ -666,15 +719,9 @@ AlterRole(AlterRoleStmt *stmt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* valid until */
|
/* valid until */
|
||||||
if (validUntil)
|
new_record[Anum_pg_authid_rolvaliduntil - 1] = validUntil_datum;
|
||||||
{
|
new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null;
|
||||||
new_record[Anum_pg_authid_rolvaliduntil - 1] =
|
new_record_repl[Anum_pg_authid_rolvaliduntil - 1] = true;
|
||||||
DirectFunctionCall3(timestamptz_in,
|
|
||||||
CStringGetDatum(validUntil),
|
|
||||||
ObjectIdGetDatum(InvalidOid),
|
|
||||||
Int32GetDatum(-1));
|
|
||||||
new_record_repl[Anum_pg_authid_rolvaliduntil - 1] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
new_tuple = heap_modify_tuple(tuple, pg_authid_dsc, new_record,
|
new_tuple = heap_modify_tuple(tuple, pg_authid_dsc, new_record,
|
||||||
new_record_nulls, new_record_repl);
|
new_record_nulls, new_record_repl);
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* Commands for manipulating roles (formerly called users).
|
* Commands for manipulating roles (formerly called users).
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/commands/user.h,v 1.30 2006/10/04 00:30:08 momjian Exp $
|
* $PostgreSQL: pgsql/src/include/commands/user.h,v 1.31 2009/11/18 21:57:56 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -14,6 +14,14 @@
|
|||||||
#include "nodes/parsenodes.h"
|
#include "nodes/parsenodes.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* Hook to check passwords in CreateRole() and AlterRole() */
|
||||||
|
#define PASSWORD_TYPE_PLAINTEXT 0
|
||||||
|
#define PASSWORD_TYPE_MD5 1
|
||||||
|
|
||||||
|
typedef void (*check_password_hook_type) (const char *username, const char *password, int password_type, Datum validuntil_time, bool validuntil_null);
|
||||||
|
|
||||||
|
extern PGDLLIMPORT check_password_hook_type check_password_hook;
|
||||||
|
|
||||||
extern void CreateRole(CreateRoleStmt *stmt);
|
extern void CreateRole(CreateRoleStmt *stmt);
|
||||||
extern void AlterRole(AlterRoleStmt *stmt);
|
extern void AlterRole(AlterRoleStmt *stmt);
|
||||||
extern void AlterRoleSet(AlterRoleSetStmt *stmt);
|
extern void AlterRoleSet(AlterRoleSetStmt *stmt);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user