diff options
Diffstat (limited to 'src/backend/libpq/crypt.c')
-rw-r--r-- | src/backend/libpq/crypt.c | 204 |
1 files changed, 151 insertions, 53 deletions
diff --git a/src/backend/libpq/crypt.c b/src/backend/libpq/crypt.c index 1386ff74ac..6e6555503a 100644 --- a/src/backend/libpq/crypt.c +++ b/src/backend/libpq/crypt.c @@ -4,6 +4,11 @@ * Look into pg_user and check the encrypted password with the one * passed in from the frontend. * + * Modification History + * + * Dec 17, 1997 - Todd A. Brandys + * Orignal Version Completed. + * * *------------------------------------------------------------------------- */ @@ -18,72 +23,163 @@ #include "postgres.h" #include "miscadmin.h" -#include "libpq/crypt.h" #include "utils/nabstime.h" -#include "utils/palloc.h" #include "storage/fd.h" +#include "libpq/crypt.h" + +char** pwd_cache = NULL; +int pwd_cache_count = 0; + +/*-------------------------------------------------------------------------*/ char* crypt_getpwdfilename() { - static char* filename = NULL; + static char* pfnam = NULL; - if (!filename) { - filename = (char*)palloc(strlen(DataDir) + strlen(CRYPT_PWD_FILE) + 2); - sprintf(filename, "%s/%s", DataDir, CRYPT_PWD_FILE); + if (!pfnam) { + pfnam = (char*)malloc(strlen(DataDir) + strlen(CRYPT_PWD_FILE) + 2); + sprintf(pfnam, "%s/%s", DataDir, CRYPT_PWD_FILE); } - return filename; + return pfnam; +} + +/*-------------------------------------------------------------------------*/ + +char* crypt_getpwdreloadfilename() { + + static char* rpfnam = NULL; + + if (!rpfnam) { + char* pwdfilename; + + pwdfilename = crypt_getpwdfilename(); + rpfnam = (char*)malloc(strlen(pwdfilename) + strlen(CRYPT_PWD_RELOAD_SUFX) + 1); + sprintf(rpfnam, "%s%s", pwdfilename, CRYPT_PWD_RELOAD_SUFX); + } + + return rpfnam; } /*-------------------------------------------------------------------------*/ static FILE* crypt_openpwdfile() { - char* filename; + FILE* pwdfile; filename = crypt_getpwdfilename(); - return (AllocateFile(filename, "r")); + pwdfile = AllocateFile(filename, "r"); + + return pwdfile; } /*-------------------------------------------------------------------------*/ static -void crypt_parsepwdfile(FILE* datafile, char** login, char** pwd, char** valdate) { +int compar_user(const void* user_a, const void* user_b) { - char buffer[256]; - char* parse; - int count, - i; + int min, + value; + char* login_a; + char* login_b; - fgets(buffer, 256, datafile); - parse = buffer; + login_a = *((char**)user_a); + login_b = *((char**)user_b); - /* store a copy of user login to return + /* We only really want to compare the user logins which are first. We look + * for the first SEPSTR char getting the number of chars there are before it. + * We only need to compare to the min count from the two strings. */ - count = strcspn(parse, "#"); - *login = (char*)palloc(count + 1); - strncpy(*login, parse, count); - (*login)[count] = '\0'; - parse += (count + 1); + min = strcspn(login_a, CRYPT_PWD_FILE_SEPSTR); + value = strcspn(login_b, CRYPT_PWD_FILE_SEPSTR); + if (value < min) + min = value; + + /* We add one to min so that the separator character is included in the + * comparison. Why? I believe this will prevent logins that are proper + * prefixes of other logins from being 'masked out'. Being conservative! + */ + return strncmp(login_a, login_b, min + 1); +} + +/*-------------------------------------------------------------------------*/ + +static +void crypt_loadpwdfile() { + + char* filename; + int result; + FILE* pwd_file; + char buffer[256]; + + filename = crypt_getpwdreloadfilename(); + result = unlink(filename); + + /* We want to delete the flag file before reading the contents of the pg_pwd + * file. If result == 0 then the unlink of the reload file was successful. + * This means that a backend performed a COPY of the pg_user file to + * pg_pwd. Therefore we must now do a reload. + */ + if (!pwd_cache || !result) { + if (pwd_cache) { /* free the old data only if this is a reload */ + while (pwd_cache_count--) { + free((void*)pwd_cache[pwd_cache_count]); + } + free((void*)pwd_cache); + pwd_cache = NULL; + pwd_cache_count = 0; + } + + if (!(pwd_file = crypt_openpwdfile())) + return; + + /* Here is where we load the data from pg_pwd. + */ + while (fgets(buffer, 256, pwd_file) != NULL) { + /* We must remove the return char at the end of the string, as this will + * affect the correct parsing of the password entry. + */ + if (buffer[(result = strlen(buffer) - 1)] == '\n') + buffer[result] = '\0'; + + pwd_cache = (char**)realloc((void*)pwd_cache, sizeof(char*) * (pwd_cache_count + 1)); + pwd_cache[pwd_cache_count++] = strdup(buffer); + } + fclose(pwd_file); + + /* Now sort the entries in the cache for faster searching later. + */ + qsort((void*)pwd_cache, pwd_cache_count, sizeof(char*), compar_user); + } +} + +/*-------------------------------------------------------------------------*/ + +static +void crypt_parsepwdentry(char* buffer, char** pwd, char** valdate) { + + char* parse = buffer; + int count, + i; /* skip to the password field */ - for (i = 0; i < 5; i++) - parse += (strcspn(parse, "#") + 1); + for (i = 0; i < 6; i++) + parse += (strcspn(parse, CRYPT_PWD_FILE_SEPSTR) + 1); /* store a copy of user password to return */ - count = strcspn(parse, "#"); - *pwd = (char*)palloc(count + 1); + count = strcspn(parse, CRYPT_PWD_FILE_SEPSTR); + *pwd = (char*)malloc(count + 1); strncpy(*pwd, parse, count); (*pwd)[count] = '\0'; parse += (count + 1); /* store a copy of date login becomes invalid */ - count = strcspn(parse, "#"); - *valdate = (char*)palloc(count + 1); + count = strcspn(parse, CRYPT_PWD_FILE_SEPSTR); + *valdate = (char*)malloc(count + 1); strncpy(*valdate, parse, count); (*valdate)[count] = '\0'; parse += (count + 1); @@ -92,33 +188,33 @@ void crypt_parsepwdfile(FILE* datafile, char** login, char** pwd, char** valdate /*-------------------------------------------------------------------------*/ static -void crypt_getloginfo(const char* user, char** passwd, char** valuntil) { +int crypt_getloginfo(const char* user, char** passwd, char** valuntil) { - FILE* datafile; - char* login; char* pwd; char* valdate; + void* fakeout; *passwd = NULL; *valuntil = NULL; + crypt_loadpwdfile(); - if (!(datafile = crypt_openpwdfile())) - return; + if (pwd_cache) { + char** pwd_entry; + char user_search[NAMEDATALEN + 2]; - while (!feof(datafile)) { - crypt_parsepwdfile(datafile, &login, &pwd, &valdate); - if (!strcmp(login, user)) { - pfree((void*)login); + sprintf(user_search, "%s\t", user); + fakeout = (void*)&user_search; + if ((pwd_entry = (char**)bsearch((void*)&fakeout, (void*)pwd_cache, pwd_cache_count, sizeof(char*), compar_user))) { + crypt_parsepwdentry(*pwd_entry, &pwd, &valdate); *passwd = pwd; *valuntil = valdate; - fclose(datafile); - return; + return STATUS_OK; } - pfree((void*)login); - pfree((void*)pwd); - pfree((void*)valdate); + + return STATUS_OK; } - fclose(datafile); + + return STATUS_ERROR; } /*-------------------------------------------------------------------------*/ @@ -128,16 +224,17 @@ MsgType crypt_salt(const char* user) { char* passwd; char* valuntil; - crypt_getloginfo(user, &passwd, &valuntil); + if (crypt_getloginfo(user, &passwd, &valuntil) == STATUS_ERROR) + return STARTUP_UNSALT_MSG; if (passwd == NULL || *passwd == '\0' || !strcmp(passwd, "\\N")) { - if (passwd) pfree((void*)passwd); - if (valuntil) pfree((void*)valuntil); + if (passwd) free((void*)passwd); + if (valuntil) free((void*)valuntil); return STARTUP_UNSALT_MSG; } - pfree((void*)passwd); - if (valuntil) pfree((void*)valuntil); + free((void*)passwd); + if (valuntil) free((void*)valuntil); return STARTUP_SALT_MSG; } @@ -152,11 +249,12 @@ int crypt_verify(Port* port, const char* user, const char* pgpass) { AbsoluteTime vuntil, current; - crypt_getloginfo(user, &passwd, &valuntil); + if (crypt_getloginfo(user, &passwd, &valuntil) == STATUS_ERROR) + return STATUS_ERROR; if (passwd == NULL || *passwd == '\0') { - if (passwd) pfree((void*)passwd); - if (valuntil) pfree((void*)valuntil); + if (passwd) free((void*)passwd); + if (valuntil) free((void*)valuntil); return STATUS_ERROR; } @@ -175,8 +273,8 @@ int crypt_verify(Port* port, const char* user, const char* pgpass) { retval = STATUS_OK; } - pfree((void*)passwd); - if (valuntil) pfree((void*)valuntil); + free((void*)passwd); + if (valuntil) free((void*)valuntil); return retval; } |