Query in SQL function still not schema-safe; add a couple
[PostgreSQL.git] / src / backend / libpq / crypt.c
blobd5cd2204ef02688b57866ead534b9c684f97db44
1 /*-------------------------------------------------------------------------
3 * crypt.c
4 * Look into the password file and check the encrypted password with
5 * the one passed in from the frontend.
7 * Original coding by Todd A. Brandys
9 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
10 * Portions Copyright (c) 1994, Regents of the University of California
12 * $PostgreSQL$
14 *-------------------------------------------------------------------------
16 #include "postgres.h"
18 #include <unistd.h>
19 #ifdef HAVE_CRYPT_H
20 #include <crypt.h>
21 #endif
23 #include "libpq/crypt.h"
24 #include "libpq/md5.h"
27 int
28 md5_crypt_verify(const Port *port, const char *role, char *client_pass)
30 char *shadow_pass = NULL,
31 *valuntil = NULL,
32 *crypt_pwd;
33 int retval = STATUS_ERROR;
34 List **line;
35 ListCell *token;
36 char *crypt_client_pass = client_pass;
38 if ((line = get_role_line(role)) == NULL)
39 return STATUS_ERROR;
41 /* Skip over rolename */
42 token = list_head(*line);
43 if (token)
44 token = lnext(token);
45 if (token)
47 shadow_pass = (char *) lfirst(token);
48 token = lnext(token);
49 if (token)
50 valuntil = (char *) lfirst(token);
53 if (shadow_pass == NULL || *shadow_pass == '\0')
54 return STATUS_ERROR;
57 * Compare with the encrypted or plain password depending on the
58 * authentication method being used for this connection.
60 switch (port->hba->auth_method)
62 case uaMD5:
63 crypt_pwd = palloc(MD5_PASSWD_LEN + 1);
64 if (isMD5(shadow_pass))
66 /* stored password already encrypted, only do salt */
67 if (!pg_md5_encrypt(shadow_pass + strlen("md5"),
68 (char *) port->md5Salt,
69 sizeof(port->md5Salt), crypt_pwd))
71 pfree(crypt_pwd);
72 return STATUS_ERROR;
75 else
77 /* stored password is plain, double-encrypt */
78 char *crypt_pwd2 = palloc(MD5_PASSWD_LEN + 1);
80 if (!pg_md5_encrypt(shadow_pass,
81 port->user_name,
82 strlen(port->user_name),
83 crypt_pwd2))
85 pfree(crypt_pwd);
86 pfree(crypt_pwd2);
87 return STATUS_ERROR;
89 if (!pg_md5_encrypt(crypt_pwd2 + strlen("md5"),
90 port->md5Salt,
91 sizeof(port->md5Salt),
92 crypt_pwd))
94 pfree(crypt_pwd);
95 pfree(crypt_pwd2);
96 return STATUS_ERROR;
98 pfree(crypt_pwd2);
100 break;
101 default:
102 if (isMD5(shadow_pass))
104 /* Encrypt user-supplied password to match stored MD5 */
105 crypt_client_pass = palloc(MD5_PASSWD_LEN + 1);
106 if (!pg_md5_encrypt(client_pass,
107 port->user_name,
108 strlen(port->user_name),
109 crypt_client_pass))
111 pfree(crypt_client_pass);
112 return STATUS_ERROR;
115 crypt_pwd = shadow_pass;
116 break;
119 if (strcmp(crypt_client_pass, crypt_pwd) == 0)
122 * Password OK, now check to be sure we are not past valuntil
124 if (valuntil == NULL || *valuntil == '\0')
125 retval = STATUS_OK;
126 else
128 TimestampTz vuntil;
130 vuntil = DatumGetTimestampTz(DirectFunctionCall3(timestamptz_in,
131 CStringGetDatum(valuntil),
132 ObjectIdGetDatum(InvalidOid),
133 Int32GetDatum(-1)));
135 if (vuntil < GetCurrentTimestamp())
136 retval = STATUS_ERROR;
137 else
138 retval = STATUS_OK;
142 if (port->hba->auth_method == uaMD5)
143 pfree(crypt_pwd);
144 if (crypt_client_pass != client_pass)
145 pfree(crypt_client_pass);
147 return retval;