diff --git a/src/auth/pool_passwd.c b/src/auth/pool_passwd.c index bbc33b9a..deb074dc 100644 --- a/src/auth/pool_passwd.c +++ b/src/auth/pool_passwd.c @@ -24,6 +24,9 @@ #include #include +#include +#include +#include #include "pool.h" #include "auth/pool_passwd.h" @@ -38,9 +41,13 @@ #include -static FILE *passwd_fd = NULL; /* File descriptor for pool_passwd */ -static char saved_passwd_filename[POOLMAXPATHLEN + 1]; -static POOL_PASSWD_MODE pool_passwd_mode; +#define MAX_WAIT_SECOND_FOR_UNLOCK 10 + +static char saved_passwd_filename[PATH_MAX + 1]; +static void put_entry_in_passwd_file(FILE *fd, char* username, char* password); +static char *userMatchesString(char *buf, char *user); +static FILE *open_pool_passwd(bool writing); + /* * Initialize this module. @@ -48,42 +55,43 @@ static POOL_PASSWD_MODE pool_passwd_mode; * Open pool_passwd. */ void -pool_init_pool_passwd(char *pool_passwd_filename, POOL_PASSWD_MODE mode) +pool_init_pool_passwd(char *pool_passwd_filename) { - char *openmode; - - if (passwd_fd) - return; - - pool_passwd_mode = mode; - if (saved_passwd_filename[0] == '\0') { - int len = strlen(pool_passwd_filename); - + int len = strlen(pool_passwd_filename); memcpy(saved_passwd_filename, pool_passwd_filename, len); saved_passwd_filename[len] = '\0'; } +} - if (mode == POOL_PASSWD_R) - openmode = "r"; - else - openmode = "r+"; - - passwd_fd = fopen(pool_passwd_filename, openmode); +static FILE *open_pool_passwd(bool writing) +{ + FILE *passwd_fd = fopen(saved_passwd_filename, writing?"r+":"r"); if (!passwd_fd) { if (errno == ENOENT) { /* The file does not exist yet. Create it. */ - passwd_fd = fopen(pool_passwd_filename, "w+"); - if (passwd_fd) - return; + passwd_fd = fopen(saved_passwd_filename, "w+"); } - ereport(ERROR, - (errmsg("initializing pool password, failed to open file:\"%s\"", pool_passwd_filename), - errdetail("file open failed with error:\"%s\"", strerror(errno)))); } + return passwd_fd; +} + +static void put_entry_in_passwd_file(FILE *fd, char* username, char* password) +{ + int c; + while ((c = *username++)) + { + fputc(c, fd); + } + fputc(':', fd); + while ((c = *password++)) + { + fputc(c, fd); + } + fputc('\n', fd); } /* @@ -93,84 +101,116 @@ pool_init_pool_passwd(char *pool_passwd_filename, POOL_PASSWD_MODE mode) int pool_create_passwdent(char *username, char *passwd) { - int len; - int c; - char name[MAX_USER_NAME_LEN]; - char *p; - int readlen; - - if (!passwd_fd) + FILE* pass_file = NULL; + char buf[1024]; + bool updated = false; + char tempPassFilePath[PATH_MAX]; + char lockPassFilePath[PATH_MAX]; + FILE *tmp_passwd_fd; + FILE *lock_passwd_fd; + int i = 0; + + if (strlen(passwd) <= 0) ereport(ERROR, - (errmsg("error updating password, password file descriptor is NULL"))); + (errmsg("error updating password, password not provided"))); + + /* create a temp file and lock file names */ + snprintf(tempPassFilePath, sizeof(tempPassFilePath), "%s.tmp",saved_passwd_filename); + snprintf(lockPassFilePath, sizeof(lockPassFilePath), "%s.lk",saved_passwd_filename); - if (pool_passwd_mode != POOL_PASSWD_RW) + pass_file = open_pool_passwd(true); + if (!pass_file) + { ereport(ERROR, - (errmsg("pool_create_passwdent should be called with pool_passwd opened with read/write mode"))); + (errmsg("unable to update password, failed to open \"%s\"", saved_passwd_filename), + errdetail("file open failed with error:\"%s\"", strerror(errno)))); + } - len = strlen(passwd); - if (len <= 0) + /* + * now create the temp pool_passwd file and if it already exists wait + * until it is deleted + */ + while (i++ < MAX_WAIT_SECOND_FOR_UNLOCK) + { + lock_passwd_fd = fopen(lockPassFilePath, "w+x"); + if (lock_passwd_fd) + break; + ereport(LOG, + (errmsg("some other utility is updating the pool_passwd, waiting for it to finish.."))); + sleep(1); + } + if (!lock_passwd_fd) + { ereport(ERROR, - (errmsg("error updating password, invalid password length:%d", len))); + (errmsg("unable to update password, lock file exists at:\"%s\"", lockPassFilePath), + errdetail("you may need to manually delete the file, if you think it is left by some older process"))); + } - rewind(passwd_fd); - name[0] = '\0'; + tmp_passwd_fd = fopen(tempPassFilePath, "w+"); - while (!feof(passwd_fd)) + if (!tmp_passwd_fd) { - p = name; - readlen = 0; + ereport(ERROR, + (errmsg("unable to update password, temp password file exists at:\"%s\"", tempPassFilePath), + errdetail("you may need to manually delete the file, if you think it is left by some older process"))); + } + while (!feof(pass_file) && !ferror(pass_file)) + { + char *t = buf; + int len; - while (readlen < sizeof(name)) - { - c = fgetc(passwd_fd); - if (c == EOF) - break; - else if (c == ':') - break; + if (fgets(buf, sizeof(buf), pass_file) == NULL) + break; - readlen++; - *p++ = c; + len = strlen(buf); + if (len == 0) + continue; + + if (updated) + { + fputs(buf, tmp_passwd_fd); + continue; } - *p = '\0'; + /* Remove trailing newline */ + if (buf[len - 1] == '\n') + buf[len - 1] = 0; - if (!strcmp(username, name)) + if ((t = userMatchesString(t, username)) == NULL) { - /* User name found. Update password. */ - while ((c = *passwd++)) - { - fputc(c, passwd_fd); - } - fputc('\n', passwd_fd); - return 0; + /* this is record of different user */ + buf[len - 1] = '\n'; + fputs(buf, tmp_passwd_fd); + continue; } else { - /* Skip password */ - while ((c = fgetc(passwd_fd)) != EOF && - c != '\n') - ; - } - } + /*update*/ + updated = true; + put_entry_in_passwd_file(tmp_passwd_fd, username, passwd); - fseek(passwd_fd, 0, SEEK_END); - - /* - * Not found the user name. Create a new entry. - */ - while ((c = *username++)) - { - fputc(c, passwd_fd); + } } - fputc(':', passwd_fd); - while ((c = *passwd++)) + if (!updated) { - fputc(c, passwd_fd); + /* it easy just append the new user:password at the end */ + fseek(pass_file, 0, SEEK_END); + put_entry_in_passwd_file(pass_file, username, passwd); } - fputc('\n', passwd_fd); - return 0; + fclose(pass_file); + fclose(tmp_passwd_fd); + if (updated) + rename(tempPassFilePath, saved_passwd_filename); + else + unlink(tempPassFilePath); + + fclose(lock_passwd_fd); + unlink(lockPassFilePath); +return 0; } + + /* * Get password in pool_passwd by username. Returns NULL if specified * entry does not exist or error occurred. @@ -184,16 +224,17 @@ pool_get_passwd(char *username) static char passwd[POOL_PASSWD_LEN + 1]; char *p; int readlen; + FILE *passwd_fd; if (!username) ereport(ERROR, (errmsg("unable to get password, username is NULL"))); + passwd_fd = open_pool_passwd(false); if (!passwd_fd) ereport(ERROR, (errmsg("unable to get password, password file descriptor is NULL"))); - rewind(passwd_fd); name[0] = '\0'; while (!feof(passwd_fd)) @@ -227,6 +268,7 @@ pool_get_passwd(char *username) readlen++; } *p = '\0'; + fclose(passwd_fd); return passwd; } else @@ -237,6 +279,7 @@ pool_get_passwd(char *username) ; } } + fclose(passwd_fd); return NULL; } @@ -332,26 +375,26 @@ pool_get_user_credentials(char *username) { PasswordMapping *pwdMapping = NULL; char buf[1024]; + FILE* pass_file; if (!username) ereport(ERROR, (errmsg("unable to get password, username is NULL"))); - - if (!passwd_fd) + pass_file = open_pool_passwd(false); + if (!pass_file) { ereport(WARNING, - (errmsg("unable to get password, password file descriptor is NULL"))); + (errmsg("unable to get password, could not open password file"))); return NULL; } - rewind(passwd_fd); - while (!feof(passwd_fd) && !ferror(passwd_fd)) + while (!feof(pass_file) && !ferror(pass_file)) { char *t = buf; char *tok; int len; - if (fgets(buf, sizeof(buf), passwd_fd) == NULL) + if (fgets(buf, sizeof(buf), pass_file) == NULL) break; len = strlen(buf); @@ -394,6 +437,7 @@ pool_get_user_credentials(char *username) } break; } + fclose(pass_file); return pwdMapping; } @@ -424,24 +468,10 @@ pool_delete_passwdent(char *username) { } -/* - * Finish this moil. Close pool_passwd. - */ -void -pool_finish_pool_passwd(void) -{ - if (passwd_fd) - { - fclose(passwd_fd); - passwd_fd = NULL; - } -} - void pool_reopen_passwd_file(void) { - pool_finish_pool_passwd(); - pool_init_pool_passwd(saved_passwd_filename, pool_passwd_mode); + pool_init_pool_passwd(saved_passwd_filename); } /* diff --git a/src/include/auth/pool_passwd.h b/src/include/auth/pool_passwd.h index c00cb960..0283f54d 100644 --- a/src/include/auth/pool_passwd.h +++ b/src/include/auth/pool_passwd.h @@ -40,14 +40,6 @@ #define PASSWORD_SCRAM_PREFIX "SCRAM-SHA-256$" #define PASSWORD_TEXT_PREFIX "TEXT" -typedef enum -{ - POOL_PASSWD_R, /* open pool_passwd in read only mode. used by - * pgpool-II child main process */ - POOL_PASSWD_RW, /* open pool_passwd in read/write mode. used - * by pg_md5 command */ -} POOL_PASSWD_MODE; - typedef enum PasswordType { PASSWORD_TYPE_UNKNOWN = 0, @@ -74,11 +66,10 @@ typedef struct PasswordMapping extern PasswordMapping * pool_get_user_credentials(char *username); extern PasswordType get_password_type(const char *shadow_pass); -extern void pool_init_pool_passwd(char *pool_passwd_filename, POOL_PASSWD_MODE mode); +extern void pool_init_pool_passwd(char *pool_passwd_filename); extern int pool_create_passwdent(char *username, char *passwd); extern char *pool_get_passwd(char *username); extern void pool_delete_passwdent(char *username); -extern void pool_finish_pool_passwd(void); extern void pool_reopen_passwd_file(void); extern char *get_decrypted_password(const char *shadow_pass); extern char *read_pool_key(char *key_file_path); diff --git a/src/main/main.c b/src/main/main.c index 5392dac2..41fb7ad8 100644 --- a/src/main/main.c +++ b/src/main/main.c @@ -353,7 +353,7 @@ main(int argc, char **argv) dirp = dirname(dirnamebuf); snprintf(pool_passwd, sizeof(pool_passwd), "%s/%s", dirp, pool_config->pool_passwd); - pool_init_pool_passwd(pool_passwd, POOL_PASSWD_R); + pool_init_pool_passwd(pool_passwd); } pool_semaphore_create(MAX_NUM_SEMAPHORES); diff --git a/src/tools/pgenc/pg_enc.c b/src/tools/pgenc/pg_enc.c index 12c2361f..8731a1dc 100644 --- a/src/tools/pgenc/pg_enc.c +++ b/src/tools/pgenc/pg_enc.c @@ -321,7 +321,7 @@ update_pool_passwd(char *conf_file, char *username, char *password, char *key) dirp = dirname(dirnamebuf); snprintf(pool_passwd, sizeof(pool_passwd), "%s/%s", dirp, pool_config->pool_passwd); - pool_init_pool_passwd(pool_passwd, POOL_PASSWD_RW); + pool_init_pool_passwd(pool_passwd); if (username == NULL || strlen(username) == 0) { @@ -356,7 +356,6 @@ update_pool_passwd(char *conf_file, char *username, char *password, char *key) b64_enc[len] = 0; pool_create_passwdent(user, (char *) b64_enc); - pool_finish_pool_passwd(); } static void diff --git a/src/tools/pgmd5/pg_md5.c b/src/tools/pgmd5/pg_md5.c index cf37e890..26206d0d 100644 --- a/src/tools/pgmd5/pg_md5.c +++ b/src/tools/pgmd5/pg_md5.c @@ -213,7 +213,7 @@ update_pool_passwd(char *conf_file, char *username, char *password) dirp = dirname(dirnamebuf); snprintf(pool_passwd, sizeof(pool_passwd), "%s/%s", dirp, pool_config->pool_passwd); - pool_init_pool_passwd(pool_passwd, POOL_PASSWD_RW); + pool_init_pool_passwd(pool_passwd); if (strlen(username)) { @@ -233,7 +233,6 @@ update_pool_passwd(char *conf_file, char *username, char *password) pg_md5_encrypt(password, pw->pw_name, strlen(pw->pw_name), md5); pool_create_passwdent(pw->pw_name, md5); } - pool_finish_pool_passwd(); } static void