PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
passwordcheck.c File Reference
#include "postgres.h"
#include <ctype.h>
#include <limits.h>
#include "commands/user.h"
#include "fmgr.h"
#include "libpq/crypt.h"
Include dependency graph for passwordcheck.c:

Go to the source code of this file.

Functions

 PG_MODULE_MAGIC_EXT (.name="passwordcheck",.version=PG_VERSION)
 
static void check_password (const char *username, const char *shadow_pass, PasswordType password_type, Datum validuntil_time, bool validuntil_null)
 
void _PG_init (void)
 

Variables

static check_password_hook_type prev_check_password_hook = NULL
 
static int min_password_length = 8
 

Function Documentation

◆ _PG_init()

void _PG_init ( void  )

Definition at line 149 of file passwordcheck.c.

150{
151 /* Define custom GUC variables. */
152 DefineCustomIntVariable("passwordcheck.min_password_length",
153 "Minimum allowed password length.",
154 NULL,
156 8,
157 0, INT_MAX,
158 PGC_SUSET,
160 NULL, NULL, NULL);
161
162 MarkGUCPrefixReserved("passwordcheck");
163
164 /* activate password checks when the module is loaded */
167}
void MarkGUCPrefixReserved(const char *className)
Definition: guc.c:5280
void DefineCustomIntVariable(const char *name, const char *short_desc, const char *long_desc, int *valueAddr, int bootValue, int minValue, int maxValue, GucContext context, int flags, GucIntCheckHook check_hook, GucIntAssignHook assign_hook, GucShowHook show_hook)
Definition: guc.c:5159
@ PGC_SUSET
Definition: guc.h:78
#define GUC_UNIT_BYTE
Definition: guc.h:236
static int min_password_length
Definition: passwordcheck.c:37
static void check_password(const char *username, const char *shadow_pass, PasswordType password_type, Datum validuntil_time, bool validuntil_null)
Definition: passwordcheck.c:57
static check_password_hook_type prev_check_password_hook
Definition: passwordcheck.c:34
check_password_hook_type check_password_hook
Definition: user.c:92

References check_password(), check_password_hook, DefineCustomIntVariable(), GUC_UNIT_BYTE, MarkGUCPrefixReserved(), min_password_length, PGC_SUSET, and prev_check_password_hook.

◆ check_password()

static void check_password ( const char *  username,
const char *  shadow_pass,
PasswordType  password_type,
Datum  validuntil_time,
bool  validuntil_null 
)
static

Definition at line 57 of file passwordcheck.c.

62{
65 password_type, validuntil_time,
66 validuntil_null);
67
68 if (password_type != PASSWORD_TYPE_PLAINTEXT)
69 {
70 /*
71 * Unfortunately we cannot perform exhaustive checks on encrypted
72 * passwords - we are restricted to guessing. (Alternatively, we could
73 * insist on the password being presented non-encrypted, but that has
74 * its own security disadvantages.)
75 *
76 * We only check for username = password.
77 */
78 const char *logdetail = NULL;
79
80 if (plain_crypt_verify(username, shadow_pass, username, &logdetail) == STATUS_OK)
82 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
83 errmsg("password must not equal user name")));
84 }
85 else
86 {
87 /*
88 * For unencrypted passwords we can perform better checks
89 */
90 const char *password = shadow_pass;
91 int pwdlen = strlen(password);
92 int i;
93 bool pwd_has_letter,
94 pwd_has_nonletter;
95#ifdef USE_CRACKLIB
96 const char *reason;
97#endif
98
99 /* enforce minimum length */
100 if (pwdlen < min_password_length)
102 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
103 errmsg("password is too short"),
104 errdetail("password must be at least \"passwordcheck.min_password_length\" (%d) bytes long",
106
107 /* check if the password contains the username */
108 if (strstr(password, username))
110 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
111 errmsg("password must not contain user name")));
112
113 /* check if the password contains both letters and non-letters */
114 pwd_has_letter = false;
115 pwd_has_nonletter = false;
116 for (i = 0; i < pwdlen; i++)
117 {
118 /*
119 * isalpha() does not work for multibyte encodings but let's
120 * consider non-ASCII characters non-letters
121 */
122 if (isalpha((unsigned char) password[i]))
123 pwd_has_letter = true;
124 else
125 pwd_has_nonletter = true;
126 }
127 if (!pwd_has_letter || !pwd_has_nonletter)
129 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
130 errmsg("password must contain both letters and nonletters")));
131
132#ifdef USE_CRACKLIB
133 /* call cracklib to check password */
134 if ((reason = FascistCheck(password, CRACKLIB_DICTPATH)))
136 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
137 errmsg("password is easily cracked"),
138 errdetail_log("cracklib diagnostic: %s", reason)));
139#endif
140 }
141
142 /* all checks passed, password is ok */
143}
#define STATUS_OK
Definition: c.h:1140
int plain_crypt_verify(const char *role, const char *shadow_pass, const char *client_pass, const char **logdetail)
Definition: crypt.c:256
@ PASSWORD_TYPE_PLAINTEXT
Definition: crypt.h:42
int errdetail(const char *fmt,...)
Definition: elog.c:1204
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
int errdetail_log(const char *fmt,...)
Definition: elog.c:1252
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
static char * username
Definition: initdb.c:153
int i
Definition: isn.c:77
static char * password
Definition: streamutil.c:51

References ereport, errcode(), errdetail(), errdetail_log(), errmsg(), ERROR, i, min_password_length, password, PASSWORD_TYPE_PLAINTEXT, plain_crypt_verify(), prev_check_password_hook, STATUS_OK, and username.

Referenced by _PG_init().

◆ PG_MODULE_MAGIC_EXT()

PG_MODULE_MAGIC_EXT ( name = "passwordcheck",
version = PG_VERSION 
)

Variable Documentation

◆ min_password_length

int min_password_length = 8
static

Definition at line 37 of file passwordcheck.c.

Referenced by _PG_init(), and check_password().

◆ prev_check_password_hook

check_password_hook_type prev_check_password_hook = NULL
static

Definition at line 34 of file passwordcheck.c.

Referenced by _PG_init(), and check_password().