PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
passwordcheck.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * passwordcheck.c
4  *
5  *
6  * Copyright (c) 2009-2017, 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 
19 #ifdef USE_CRACKLIB
20 #include <crack.h>
21 #endif
22 
23 #include "commands/user.h"
24 #include "libpq/crypt.h"
25 #include "fmgr.h"
26 
28 
29 /* passwords shorter than this will be rejected */
30 #define MIN_PWD_LENGTH 8
31 
32 extern void _PG_init(void);
33 
34 /*
35  * check_password
36  *
37  * performs checks on an encrypted or unencrypted password
38  * ereport's if not acceptable
39  *
40  * username: name of role being created or changed
41  * password: new password (possibly already encrypted)
42  * password_type: PASSWORD_TYPE_* code, to indicate if the password is
43  * in plaintext or encrypted form.
44  * validuntil_time: password expiration time, as a timestamptz Datum
45  * validuntil_null: true if password expiration time is NULL
46  *
47  * This sample implementation doesn't pay any attention to the password
48  * expiration time, but you might wish to insist that it be non-null and
49  * not too far in the future.
50  */
51 static void
53  const char *shadow_pass,
54  PasswordType password_type,
55  Datum validuntil_time,
56  bool validuntil_null)
57 {
58  if (password_type != PASSWORD_TYPE_PLAINTEXT)
59  {
60  /*
61  * Unfortunately we cannot perform exhaustive checks on encrypted
62  * passwords - we are restricted to guessing. (Alternatively, we could
63  * insist on the password being presented non-encrypted, but that has
64  * its own security disadvantages.)
65  *
66  * We only check for username = password.
67  */
68  char *logdetail;
69 
70  if (plain_crypt_verify(username, shadow_pass, username, &logdetail) == STATUS_OK)
71  ereport(ERROR,
72  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
73  errmsg("password must not contain user name")));
74  }
75  else
76  {
77  /*
78  * For unencrypted passwords we can perform better checks
79  */
80  const char *password = shadow_pass;
81  int pwdlen = strlen(password);
82  int i;
83  bool pwd_has_letter,
84  pwd_has_nonletter;
85 
86  /* enforce minimum length */
87  if (pwdlen < MIN_PWD_LENGTH)
88  ereport(ERROR,
89  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
90  errmsg("password is too short")));
91 
92  /* check if the password contains the username */
93  if (strstr(password, username))
94  ereport(ERROR,
95  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
96  errmsg("password must not contain user name")));
97 
98  /* check if the password contains both letters and non-letters */
99  pwd_has_letter = false;
100  pwd_has_nonletter = false;
101  for (i = 0; i < pwdlen; i++)
102  {
103  /*
104  * isalpha() does not work for multibyte encodings but let's
105  * consider non-ASCII characters non-letters
106  */
107  if (isalpha((unsigned char) password[i]))
108  pwd_has_letter = true;
109  else
110  pwd_has_nonletter = true;
111  }
112  if (!pwd_has_letter || !pwd_has_nonletter)
113  ereport(ERROR,
114  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
115  errmsg("password must contain both letters and nonletters")));
116 
117 #ifdef USE_CRACKLIB
118  /* call cracklib to check password */
119  if (FascistCheck(password, CRACKLIB_DICTPATH))
120  ereport(ERROR,
121  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
122  errmsg("password is easily cracked")));
123 #endif
124  }
125 
126  /* all checks passed, password is ok */
127 }
128 
129 /*
130  * Module initialization function
131  */
132 void
133 _PG_init(void)
134 {
135  /* activate password checks when the module is loaded */
137 }
static char password[100]
Definition: streamutil.c:41
PG_MODULE_MAGIC
Definition: passwordcheck.c:27
static void check_password(const char *username, const char *shadow_pass, PasswordType password_type, Datum validuntil_time, bool validuntil_null)
Definition: passwordcheck.c:52
int errcode(int sqlerrcode)
Definition: elog.c:575
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
#define STATUS_OK
Definition: c.h:975
int plain_crypt_verify(const char *role, const char *shadow_pass, const char *client_pass, char **logdetail)
Definition: crypt.c:224
uintptr_t Datum
Definition: postgres.h:372
PasswordType
Definition: crypt.h:27
static char * username
Definition: initdb.c:131
void _PG_init(void)
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
check_password_hook_type check_password_hook
Definition: user.c:50
#define MIN_PWD_LENGTH
Definition: passwordcheck.c:30