30
30
31
31
32
32
/*
33
- * Check given password for given user, and return STATUS_OK or STATUS_ERROR .
33
+ * Fetch stored password for a user, for authentication .
34
34
*
35
- * 'client_pass' is the password response given by the remote user. If
36
- * 'md5_salt' is not NULL, it is a response to an MD5 authentication
37
- * challenge, with the given salt. Otherwise, it is a plaintext password.
35
+ * Returns STATUS_OK on success. On error, returns STATUS_ERROR, and stores
36
+ * a palloc'd string describing the reason, for the postmaster log, in
37
+ * *logdetail. The error reason should *not* be sent to the client, to avoid
38
+ * giving away user information!
38
39
*
39
- * In the error case, optionally store a palloc'd string at *logdetail
40
- * that will be sent to the postmaster log (but not the client).
40
+ * If the password is expired, it is still returned in *shadow_pass, but the
41
+ * return code is STATUS_ERROR. On other errors, *shadow_pass is set to
42
+ * NULL.
41
43
*/
42
44
int
43
- md5_crypt_verify (const char * role , char * client_pass ,
44
- char * md5_salt , int md5_salt_len , char * * logdetail )
45
+ get_role_password (const char * role , char * * shadow_pass , char * * logdetail )
45
46
{
46
47
int retval = STATUS_ERROR ;
47
- char * shadow_pass ,
48
- * crypt_pwd ;
49
48
TimestampTz vuntil = 0 ;
50
- char * crypt_client_pass = client_pass ;
51
49
HeapTuple roleTup ;
52
50
Datum datum ;
53
51
bool isnull ;
54
52
53
+ * shadow_pass = NULL ;
54
+
55
55
/* Get role info from pg_authid */
56
56
roleTup = SearchSysCache1 (AUTHNAME , PointerGetDatum (role ));
57
57
if (!HeapTupleIsValid (roleTup ))
@@ -70,7 +70,7 @@ md5_crypt_verify(const char *role, char *client_pass,
70
70
role );
71
71
return STATUS_ERROR ; /* user has no password */
72
72
}
73
- shadow_pass = TextDatumGetCString (datum );
73
+ * shadow_pass = TextDatumGetCString (datum );
74
74
75
75
datum = SysCacheGetAttr (AUTHNAME , roleTup ,
76
76
Anum_pg_authid_rolvaliduntil , & isnull );
@@ -79,104 +79,151 @@ md5_crypt_verify(const char *role, char *client_pass,
79
79
80
80
ReleaseSysCache (roleTup );
81
81
82
- if (* shadow_pass == '\0' )
82
+ if (* * shadow_pass == '\0' )
83
83
{
84
84
* logdetail = psprintf (_ ("User \"%s\" has an empty password." ),
85
85
role );
86
+ pfree (* shadow_pass );
87
+ * shadow_pass = NULL ;
86
88
return STATUS_ERROR ; /* empty password */
87
89
}
88
90
89
91
/*
90
- * Compare with the encrypted or plain password depending on the
91
- * authentication method being used for this connection. (We do not
92
- * bother setting logdetail for pg_md5_encrypt failure: the only possible
93
- * error is out-of-memory, which is unlikely, and if it did happen adding
94
- * a psprintf call would only make things worse.)
92
+ * Password OK, now check to be sure we are not past rolvaliduntil
95
93
*/
96
- if (md5_salt )
94
+ if (isnull )
95
+ retval = STATUS_OK ;
96
+ else if (vuntil < GetCurrentTimestamp ())
97
97
{
98
- /* MD5 authentication */
99
- Assert (md5_salt_len > 0 );
100
- crypt_pwd = palloc (MD5_PASSWD_LEN + 1 );
101
- if (isMD5 (shadow_pass ))
102
- {
103
- /* stored password already encrypted, only do salt */
104
- if (!pg_md5_encrypt (shadow_pass + strlen ("md5" ),
105
- md5_salt , md5_salt_len ,
106
- crypt_pwd ))
107
- {
108
- pfree (crypt_pwd );
109
- return STATUS_ERROR ;
110
- }
111
- }
112
- else
98
+ * logdetail = psprintf (_ ("User \"%s\" has an expired password." ),
99
+ role );
100
+ retval = STATUS_ERROR ;
101
+ }
102
+ else
103
+ retval = STATUS_OK ;
104
+
105
+ return retval ;
106
+ }
107
+
108
+ /*
109
+ * Check MD5 authentication response, and return STATUS_OK or STATUS_ERROR.
110
+ *
111
+ * 'shadow_pass' is the user's correct password or password hash, as stored
112
+ * in pg_authid.rolpassword.
113
+ * 'client_pass' is the response given by the remote user to the MD5 challenge.
114
+ * 'md5_salt' is the salt used in the MD5 authentication challenge.
115
+ *
116
+ * In the error case, optionally store a palloc'd string at *logdetail
117
+ * that will be sent to the postmaster log (but not the client).
118
+ */
119
+ int
120
+ md5_crypt_verify (const char * role , const char * shadow_pass ,
121
+ const char * client_pass ,
122
+ const char * md5_salt , int md5_salt_len ,
123
+ char * * logdetail )
124
+ {
125
+ int retval ;
126
+ char crypt_pwd [MD5_PASSWD_LEN + 1 ];
127
+ char crypt_pwd2 [MD5_PASSWD_LEN + 1 ];
128
+
129
+ Assert (md5_salt_len > 0 );
130
+
131
+ /*
132
+ * Compute the correct answer for the MD5 challenge.
133
+ *
134
+ * We do not bother setting logdetail for any pg_md5_encrypt failure
135
+ * below: the only possible error is out-of-memory, which is unlikely, and
136
+ * if it did happen adding a psprintf call would only make things worse.
137
+ */
138
+ if (isMD5 (shadow_pass ))
139
+ {
140
+ /* stored password already encrypted, only do salt */
141
+ if (!pg_md5_encrypt (shadow_pass + strlen ("md5" ),
142
+ md5_salt , md5_salt_len ,
143
+ crypt_pwd ))
113
144
{
114
- /* stored password is plain, double-encrypt */
115
- char * crypt_pwd2 = palloc (MD5_PASSWD_LEN + 1 );
116
-
117
- if (!pg_md5_encrypt (shadow_pass ,
118
- role ,
119
- strlen (role ),
120
- crypt_pwd2 ))
121
- {
122
- pfree (crypt_pwd );
123
- pfree (crypt_pwd2 );
124
- return STATUS_ERROR ;
125
- }
126
- if (!pg_md5_encrypt (crypt_pwd2 + strlen ("md5" ),
127
- md5_salt , md5_salt_len ,
128
- crypt_pwd ))
129
- {
130
- pfree (crypt_pwd );
131
- pfree (crypt_pwd2 );
132
- return STATUS_ERROR ;
133
- }
134
- pfree (crypt_pwd2 );
145
+ return STATUS_ERROR ;
135
146
}
136
147
}
137
148
else
138
149
{
139
- /* Client sent password in plaintext */
140
- if (isMD5 (shadow_pass ))
150
+ /* stored password is plain, double-encrypt */
151
+ if (!pg_md5_encrypt (shadow_pass ,
152
+ role ,
153
+ strlen (role ),
154
+ crypt_pwd2 ))
141
155
{
142
- /* Encrypt user-supplied password to match stored MD5 */
143
- crypt_client_pass = palloc (MD5_PASSWD_LEN + 1 );
144
- if (!pg_md5_encrypt (client_pass ,
145
- role ,
146
- strlen (role ),
147
- crypt_client_pass ))
148
- {
149
- pfree (crypt_client_pass );
150
- return STATUS_ERROR ;
151
- }
156
+ return STATUS_ERROR ;
157
+ }
158
+ if (!pg_md5_encrypt (crypt_pwd2 + strlen ("md5" ),
159
+ md5_salt , md5_salt_len ,
160
+ crypt_pwd ))
161
+ {
162
+ return STATUS_ERROR ;
152
163
}
153
- crypt_pwd = shadow_pass ;
154
164
}
155
165
156
- if (strcmp (crypt_client_pass , crypt_pwd ) == 0 )
166
+ if (strcmp (client_pass , crypt_pwd ) == 0 )
167
+ retval = STATUS_OK ;
168
+ else
157
169
{
158
- /*
159
- * Password OK, now check to be sure we are not past rolvaliduntil
160
- */
161
- if (isnull )
162
- retval = STATUS_OK ;
163
- else if (vuntil < GetCurrentTimestamp ())
170
+ * logdetail = psprintf (_ ("Password does not match for user \"%s\"." ),
171
+ role );
172
+ retval = STATUS_ERROR ;
173
+ }
174
+
175
+ return retval ;
176
+ }
177
+
178
+ /*
179
+ * Check given password for given user, and return STATUS_OK or STATUS_ERROR.
180
+ *
181
+ * 'shadow_pass' is the user's correct password or password hash, as stored
182
+ * in pg_authid.rolpassword.
183
+ * 'client_pass' is the password given by the remote user.
184
+ *
185
+ * In the error case, optionally store a palloc'd string at *logdetail
186
+ * that will be sent to the postmaster log (but not the client).
187
+ */
188
+ int
189
+ plain_crypt_verify (const char * role , const char * shadow_pass ,
190
+ const char * client_pass ,
191
+ char * * logdetail )
192
+ {
193
+ int retval ;
194
+ char crypt_client_pass [MD5_PASSWD_LEN + 1 ];
195
+
196
+ /*
197
+ * Client sent password in plaintext. If we have an MD5 hash stored, hash
198
+ * the password the client sent, and compare the hashes. Otherwise
199
+ * compare the plaintext passwords directly.
200
+ */
201
+ if (isMD5 (shadow_pass ))
202
+ {
203
+ if (!pg_md5_encrypt (client_pass ,
204
+ role ,
205
+ strlen (role ),
206
+ crypt_client_pass ))
164
207
{
165
- * logdetail = psprintf (_ ("User \"%s\" has an expired password." ),
166
- role );
167
- retval = STATUS_ERROR ;
208
+ /*
209
+ * We do not bother setting logdetail for pg_md5_encrypt failure:
210
+ * the only possible error is out-of-memory, which is unlikely,
211
+ * and if it did happen adding a psprintf call would only make
212
+ * things worse.
213
+ */
214
+ return STATUS_ERROR ;
168
215
}
169
- else
170
- retval = STATUS_OK ;
216
+ client_pass = crypt_client_pass ;
171
217
}
218
+
219
+ if (strcmp (client_pass , shadow_pass ) == 0 )
220
+ retval = STATUS_OK ;
172
221
else
222
+ {
173
223
* logdetail = psprintf (_ ("Password does not match for user \"%s\"." ),
174
224
role );
175
-
176
- if (crypt_pwd != shadow_pass )
177
- pfree (crypt_pwd );
178
- if (crypt_client_pass != client_pass )
179
- pfree (crypt_client_pass );
225
+ retval = STATUS_ERROR ;
226
+ }
180
227
181
228
return retval ;
182
229
}
0 commit comments