1 /*-------------------------------------------------------------------------
4 * Look into pg_user and check the encrypted password with the one
5 * passed in from the frontend.
9 * Dec 17, 1997 - Todd A. Brandys
10 * Orignal Version Completed.
13 *-------------------------------------------------------------------------
25 #include "miscadmin.h"
26 #include "utils/nabstime.h"
27 #include "storage/fd.h"
28 #include "libpq/crypt.h"
30 char** pwd_cache = NULL;
31 int pwd_cache_count = 0;
33 /*-------------------------------------------------------------------------*/
35 char* crypt_getpwdfilename() {
37 static char* pfnam = NULL;
40 pfnam = (char*)malloc(strlen(DataDir) + strlen(CRYPT_PWD_FILE) + 2);
41 sprintf(pfnam, "%s/%s", DataDir, CRYPT_PWD_FILE);
47 /*-------------------------------------------------------------------------*/
49 char* crypt_getpwdreloadfilename() {
51 static char* rpfnam = NULL;
56 pwdfilename = crypt_getpwdfilename();
57 rpfnam = (char*)malloc(strlen(pwdfilename) + strlen(CRYPT_PWD_RELOAD_SUFX) + 1);
58 sprintf(rpfnam, "%s%s", pwdfilename, CRYPT_PWD_RELOAD_SUFX);
64 /*-------------------------------------------------------------------------*/
67 FILE* crypt_openpwdfile() {
71 filename = crypt_getpwdfilename();
72 pwdfile = AllocateFile(filename, "r");
77 /*-------------------------------------------------------------------------*/
80 int compar_user(const void* user_a, const void* user_b) {
87 login_a = *((char**)user_a);
88 login_b = *((char**)user_b);
90 /* We only really want to compare the user logins which are first. We look
91 * for the first SEPSTR char getting the number of chars there are before it.
92 * We only need to compare to the min count from the two strings.
94 min = strcspn(login_a, CRYPT_PWD_FILE_SEPSTR);
95 value = strcspn(login_b, CRYPT_PWD_FILE_SEPSTR);
99 /* We add one to min so that the separator character is included in the
100 * comparison. Why? I believe this will prevent logins that are proper
101 * prefixes of other logins from being 'masked out'. Being conservative!
103 return strncmp(login_a, login_b, min + 1);
106 /*-------------------------------------------------------------------------*/
109 void crypt_loadpwdfile() {
116 filename = crypt_getpwdreloadfilename();
117 result = unlink(filename);
119 /* We want to delete the flag file before reading the contents of the pg_pwd
120 * file. If result == 0 then the unlink of the reload file was successful.
121 * This means that a backend performed a COPY of the pg_user file to
122 * pg_pwd. Therefore we must now do a reload.
124 if (!pwd_cache || !result) {
125 if (pwd_cache) { /* free the old data only if this is a reload */
126 while (pwd_cache_count--) {
127 free((void*)pwd_cache[pwd_cache_count]);
129 free((void*)pwd_cache);
134 if (!(pwd_file = crypt_openpwdfile()))
137 /* Here is where we load the data from pg_pwd.
139 while (fgets(buffer, 256, pwd_file) != NULL) {
140 /* We must remove the return char at the end of the string, as this will
141 * affect the correct parsing of the password entry.
143 if (buffer[(result = strlen(buffer) - 1)] == '\n')
144 buffer[result] = '\0';
146 pwd_cache = (char**)realloc((void*)pwd_cache, sizeof(char*) * (pwd_cache_count + 1));
147 pwd_cache[pwd_cache_count++] = strdup(buffer);
151 /* Now sort the entries in the cache for faster searching later.
153 qsort((void*)pwd_cache, pwd_cache_count, sizeof(char*), compar_user);
157 /*-------------------------------------------------------------------------*/
160 void crypt_parsepwdentry(char* buffer, char** pwd, char** valdate) {
162 char* parse = buffer;
166 /* skip to the password field
168 for (i = 0; i < 6; i++)
169 parse += (strcspn(parse, CRYPT_PWD_FILE_SEPSTR) + 1);
171 /* store a copy of user password to return
173 count = strcspn(parse, CRYPT_PWD_FILE_SEPSTR);
174 *pwd = (char*)malloc(count + 1);
175 strncpy(*pwd, parse, count);
176 (*pwd)[count] = '\0';
177 parse += (count + 1);
179 /* store a copy of date login becomes invalid
181 count = strcspn(parse, CRYPT_PWD_FILE_SEPSTR);
182 *valdate = (char*)malloc(count + 1);
183 strncpy(*valdate, parse, count);
184 (*valdate)[count] = '\0';
185 parse += (count + 1);
188 /*-------------------------------------------------------------------------*/
191 int crypt_getloginfo(const char* user, char** passwd, char** valuntil) {
203 char user_search[NAMEDATALEN + 2];
205 sprintf(user_search, "%s\t", user);
206 fakeout = (void*)&user_search;
207 if ((pwd_entry = (char**)bsearch((void*)&fakeout, (void*)pwd_cache, pwd_cache_count, sizeof(char*), compar_user))) {
208 crypt_parsepwdentry(*pwd_entry, &pwd, &valdate);
220 /*-------------------------------------------------------------------------*/
222 MsgType crypt_salt(const char* user) {
227 if (crypt_getloginfo(user, &passwd, &valuntil) == STATUS_ERROR)
228 return STARTUP_UNSALT_MSG;
230 if (passwd == NULL || *passwd == '\0' || !strcmp(passwd, "\\N")) {
231 if (passwd) free((void*)passwd);
232 if (valuntil) free((void*)valuntil);
233 return STARTUP_UNSALT_MSG;
237 if (valuntil) free((void*)valuntil);
238 return STARTUP_SALT_MSG;
241 /*-------------------------------------------------------------------------*/
243 int crypt_verify(Port* port, const char* user, const char* pgpass) {
248 int retval = STATUS_ERROR;
252 if (crypt_getloginfo(user, &passwd, &valuntil) == STATUS_ERROR)
255 if (passwd == NULL || *passwd == '\0') {
256 if (passwd) free((void*)passwd);
257 if (valuntil) free((void*)valuntil);
261 crypt_pwd = crypt(passwd, port->salt);
262 if (!strcmp(pgpass, crypt_pwd)) {
263 /* check here to be sure we are not past valuntil
266 vuntil = INVALID_ABSTIME;
268 vuntil = nabstimein(valuntil);
269 current = GetCurrentAbsoluteTime();
270 if (vuntil != INVALID_ABSTIME && vuntil < current)
271 retval = STATUS_ERROR;
277 if (valuntil) free((void*)valuntil);