]> granicus.if.org Git - postgresql/blob - src/backend/libpq/crypt.c
Reduce hash size for compute_array_stats, compute_tsvector_stats.
[postgresql] / src / backend / libpq / crypt.c
1 /*-------------------------------------------------------------------------
2  *
3  * crypt.c
4  *        Look into the password file and check the encrypted password with
5  *        the one passed in from the frontend.
6  *
7  * Original coding by Todd A. Brandys
8  *
9  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
10  * Portions Copyright (c) 1994, Regents of the University of California
11  *
12  * src/backend/libpq/crypt.c
13  *
14  *-------------------------------------------------------------------------
15  */
16 #include "postgres.h"
17
18 #include <unistd.h>
19 #ifdef HAVE_CRYPT_H
20 #include <crypt.h>
21 #endif
22
23 #include "catalog/pg_authid.h"
24 #include "libpq/crypt.h"
25 #include "libpq/md5.h"
26 #include "miscadmin.h"
27 #include "utils/builtins.h"
28 #include "utils/syscache.h"
29 #include "utils/timestamp.h"
30
31
32 int
33 md5_crypt_verify(const Port *port, const char *role, char *client_pass)
34 {
35         int                     retval = STATUS_ERROR;
36         char       *shadow_pass,
37                            *crypt_pwd;
38         TimestampTz vuntil = 0;
39         char       *crypt_client_pass = client_pass;
40         HeapTuple       roleTup;
41         Datum           datum;
42         bool            isnull;
43
44         /*
45          * Disable immediate interrupts while doing database access.  (Note we
46          * don't bother to turn this back on if we hit one of the failure
47          * conditions, since we can expect we'll just exit right away anyway.)
48          */
49         ImmediateInterruptOK = false;
50
51         /* Get role info from pg_authid */
52         roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(role));
53         if (!HeapTupleIsValid(roleTup))
54                 return STATUS_ERROR;    /* no such user */
55
56         datum = SysCacheGetAttr(AUTHNAME, roleTup,
57                                                         Anum_pg_authid_rolpassword, &isnull);
58         if (isnull)
59         {
60                 ReleaseSysCache(roleTup);
61                 return STATUS_ERROR;    /* user has no password */
62         }
63         shadow_pass = TextDatumGetCString(datum);
64
65         datum = SysCacheGetAttr(AUTHNAME, roleTup,
66                                                         Anum_pg_authid_rolvaliduntil, &isnull);
67         if (!isnull)
68                 vuntil = DatumGetTimestampTz(datum);
69
70         ReleaseSysCache(roleTup);
71
72         if (*shadow_pass == '\0')
73                 return STATUS_ERROR;    /* empty password */
74
75         /* Re-enable immediate response to SIGTERM/SIGINT/timeout interrupts */
76         ImmediateInterruptOK = true;
77         /* And don't forget to detect one that already arrived */
78         CHECK_FOR_INTERRUPTS();
79
80         /*
81          * Compare with the encrypted or plain password depending on the
82          * authentication method being used for this connection.
83          */
84         switch (port->hba->auth_method)
85         {
86                 case uaMD5:
87                         crypt_pwd = palloc(MD5_PASSWD_LEN + 1);
88                         if (isMD5(shadow_pass))
89                         {
90                                 /* stored password already encrypted, only do salt */
91                                 if (!pg_md5_encrypt(shadow_pass + strlen("md5"),
92                                                                         port->md5Salt,
93                                                                         sizeof(port->md5Salt), crypt_pwd))
94                                 {
95                                         pfree(crypt_pwd);
96                                         return STATUS_ERROR;
97                                 }
98                         }
99                         else
100                         {
101                                 /* stored password is plain, double-encrypt */
102                                 char       *crypt_pwd2 = palloc(MD5_PASSWD_LEN + 1);
103
104                                 if (!pg_md5_encrypt(shadow_pass,
105                                                                         port->user_name,
106                                                                         strlen(port->user_name),
107                                                                         crypt_pwd2))
108                                 {
109                                         pfree(crypt_pwd);
110                                         pfree(crypt_pwd2);
111                                         return STATUS_ERROR;
112                                 }
113                                 if (!pg_md5_encrypt(crypt_pwd2 + strlen("md5"),
114                                                                         port->md5Salt,
115                                                                         sizeof(port->md5Salt),
116                                                                         crypt_pwd))
117                                 {
118                                         pfree(crypt_pwd);
119                                         pfree(crypt_pwd2);
120                                         return STATUS_ERROR;
121                                 }
122                                 pfree(crypt_pwd2);
123                         }
124                         break;
125                 default:
126                         if (isMD5(shadow_pass))
127                         {
128                                 /* Encrypt user-supplied password to match stored MD5 */
129                                 crypt_client_pass = palloc(MD5_PASSWD_LEN + 1);
130                                 if (!pg_md5_encrypt(client_pass,
131                                                                         port->user_name,
132                                                                         strlen(port->user_name),
133                                                                         crypt_client_pass))
134                                 {
135                                         pfree(crypt_client_pass);
136                                         return STATUS_ERROR;
137                                 }
138                         }
139                         crypt_pwd = shadow_pass;
140                         break;
141         }
142
143         if (strcmp(crypt_client_pass, crypt_pwd) == 0)
144         {
145                 /*
146                  * Password OK, now check to be sure we are not past rolvaliduntil
147                  */
148                 if (isnull)
149                         retval = STATUS_OK;
150                 else if (vuntil < GetCurrentTimestamp())
151                         retval = STATUS_ERROR;
152                 else
153                         retval = STATUS_OK;
154         }
155
156         if (port->hba->auth_method == uaMD5)
157                 pfree(crypt_pwd);
158         if (crypt_client_pass != client_pass)
159                 pfree(crypt_client_pass);
160
161         return retval;
162 }