PostgreSQL Source Code git master
Loading...
Searching...
No Matches
passwordcheck.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * passwordcheck.c
4 *
5 *
6 * Copyright (c) 2009-2026, PostgreSQL Global Development Group
7 *
8 * Author: Laurenz Albe <laurenz.albe@wien.gv.at>
9 *
10 * IDENTIFICATION
11 * contrib/passwordcheck/passwordcheck.c
12 *
13 *-------------------------------------------------------------------------
14 */
15#include "postgres.h"
16
17#include <ctype.h>
18#include <limits.h>
19
20#ifdef USE_CRACKLIB
21#include <crack.h>
22#endif
23
24#include "commands/user.h"
25#include "fmgr.h"
26#include "libpq/crypt.h"
27
29 .name = "passwordcheck",
30 .version = PG_VERSION
31);
32
33/* Saved hook value */
35
36/* GUC variables */
37static int min_password_length = 8;
38
39/*
40 * check_password
41 *
42 * performs checks on an encrypted or unencrypted password
43 * ereport's if not acceptable
44 *
45 * username: name of role being created or changed
46 * password: new password (possibly already encrypted)
47 * password_type: PASSWORD_TYPE_* code, to indicate if the password is
48 * in plaintext or encrypted form.
49 * validuntil_time: password expiration time, as a timestamptz Datum
50 * validuntil_null: true if password expiration time is NULL
51 *
52 * This sample implementation doesn't pay any attention to the password
53 * expiration time, but you might wish to insist that it be non-null and
54 * not too far in the future.
55 */
56static void
58 const char *shadow_pass,
61 bool validuntil_null)
62{
67
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
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,
95#ifdef USE_CRACKLIB
96 const char *reason;
97#endif
98
99 /* enforce minimum length */
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 */
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 }
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)))
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}
144
145/*
146 * Module initialization function
147 */
148void
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}
#define STATUS_OK
Definition c.h:1158
int plain_crypt_verify(const char *role, const char *shadow_pass, const char *client_pass, const char **logdetail)
Definition crypt.c:256
PasswordType
Definition crypt.h:41
@ PASSWORD_TYPE_PLAINTEXT
Definition crypt.h:42
int errdetail(const char *fmt,...)
Definition elog.c:1216
int errcode(int sqlerrcode)
Definition elog.c:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
int errdetail_log(const char *fmt,...)
Definition elog.c:1264
#define ERROR
Definition elog.h:39
#define ereport(elevel,...)
Definition elog.h:150
#define PG_MODULE_MAGIC_EXT(...)
Definition fmgr.h:540
void MarkGUCPrefixReserved(const char *className)
Definition guc.c:5148
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:5035
@ PGC_SUSET
Definition guc.h:78
#define GUC_UNIT_BYTE
Definition guc.h:236
static char * username
Definition initdb.c:153
int i
Definition isn.c:77
static int min_password_length
static void check_password(const char *username, const char *shadow_pass, PasswordType password_type, Datum validuntil_time, bool validuntil_null)
void _PG_init(void)
static check_password_hook_type prev_check_password_hook
uint64_t Datum
Definition postgres.h:70
static int fb(int x)
static char * password
Definition streamutil.c:51
check_password_hook_type check_password_hook
Definition user.c:92
void(* check_password_hook_type)(const char *username, const char *shadow_pass, PasswordType password_type, Datum validuntil_time, bool validuntil_null)
Definition user.h:25
const char * name