pgpool2.git / summary / log / commit / refs

commit    49ab80f15eb435d5df88633e6dd9d2c40c6d7c4d
Author:   Tatsuo Ishii <ishii at sraoss.co.jp>
Date:     Sun Jun 27 13:02:57 2010 +0000

    Implement md5 authentication using pool_passwd.
    Still need to rewrite documents and pgpool.config samples.


Makefile.am | 16 ++- Makefile.in | 34 ++++-- main.c | 18 ++- md5.c | 41 ++++++- pcp/md5.c | 41 ++++++- pcp_child.c | 17 --- pg_md5.c | 80 ++++++++++++- pool.h | 6 + pool_auth.c | 353 +++++++++++++++++++++++++++++++++++++++++---------------- pool_config.c | 37 ++++++ pool_config.h | 1 + pool_config.l | 37 ++++++ pool_globals.c | 27 +++++ pool_hba.c | 31 ++++- pool_type.h | 4 +- 15 files changed, 601 insertions(+), 142 deletions(-) diff --git a/Makefile.am b/Makefile.am index 5592ed02b..a377e272f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,10 +16,20 @@ pgpool_SOURCES = pool.h pool_type.h version.h pgpool.conf.sample \ pool_lobj.c pool_lobj.h \ pool_process_context.c pool_process_context.h \ pool_session_context.c pool_session_context.h \ - pool_query_context.c pool_query_context.h \ - pool_worker_child.c + pool_query_context.c pool_query_context.h \ + pool_worker_child.c \ + pool_passwd.c pool_passwd.h \ + pool_globals.c -pg_md5_SOURCES = pg_md5.c md5.c md5.h +pgpool_DEFS = -DPGPOOL_MAIN + +pg_md5_SOURCES = pg_md5.c md5.c md5.h \ + pool.h \ + pool_config.l pool_config.h \ + pool_error.c \ + pool_signal.h pool_signal.c \ + pool_passwd.c pool_passwd.h \ + pool_globals.c DEFS = @DEFS@ \ -DDEFAULT_CONFIGDIR=\"$(sysconfdir)\" diff --git a/Makefile.in b/Makefile.in index 0fa9cdc0d..1b39e4f45 100644 --- a/Makefile.in +++ b/Makefile.in @@ -60,7 +60,10 @@ am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man8dir)" \ "$(DESTDIR)$(pkgdatadir)" "$(DESTDIR)$(sysconfdir)" binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(bin_PROGRAMS) -am_pg_md5_OBJECTS = pg_md5.$(OBJEXT) md5.$(OBJEXT) +am_pg_md5_OBJECTS = pg_md5.$(OBJEXT) md5.$(OBJEXT) \ + pool_config.$(OBJEXT) pool_error.$(OBJEXT) \ + pool_signal.$(OBJEXT) pool_passwd.$(OBJEXT) \ + pool_globals.$(OBJEXT) pg_md5_OBJECTS = $(am_pg_md5_OBJECTS) pg_md5_LDADD = $(LDADD) am_pgpool_OBJECTS = main.$(OBJEXT) child.$(OBJEXT) pool_auth.$(OBJEXT) \ @@ -77,7 +80,8 @@ am_pgpool_OBJECTS = main.$(OBJEXT) child.$(OBJEXT) pool_auth.$(OBJEXT) \ pool_timestamp.$(OBJEXT) pool_proto2.$(OBJEXT) \ pool_proto_modules.$(OBJEXT) pool_lobj.$(OBJEXT) \ pool_process_context.$(OBJEXT) pool_session_context.$(OBJEXT) \ - pool_query_context.$(OBJEXT) pool_worker_child.$(OBJEXT) + pool_query_context.$(OBJEXT) pool_worker_child.$(OBJEXT) \ + pool_passwd.$(OBJEXT) pool_globals.$(OBJEXT) pgpool_OBJECTS = $(am_pgpool_OBJECTS) pgpool_DEPENDENCIES = parser/libsql-parser.a pcp/libpcp.la \ parser/nodes.o @@ -94,6 +98,7 @@ LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ LEXCOMPILE = $(LEX) $(LFLAGS) $(AM_LFLAGS) LTLEXCOMPILE = $(LIBTOOL) --mode=compile $(LEX) $(LFLAGS) $(AM_LFLAGS) +YLWRAP = $(top_srcdir)/ylwrap SOURCES = $(pg_md5_SOURCES) $(pgpool_SOURCES) DIST_SOURCES = $(pg_md5_SOURCES) $(pgpool_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ @@ -251,12 +256,23 @@ pgpool_SOURCES = pool.h pool_type.h version.h pgpool.conf.sample \ pool_lobj.c pool_lobj.h \ pool_process_context.c pool_process_context.h \ pool_session_context.c pool_session_context.h \ -< pool_query_context.c pool_query_context.h \ - pool_worker_child.c + pool_query_context.c pool_query_context.h \ + pool_worker_child.c \ + pool_passwd.c pool_passwd.h \ + pool_globals.c + +pgpool_DEFS = -DPGPOOL_MAIN +pg_md5_SOURCES = pg_md5.c md5.c md5.h \ + pool.h \ + pool_config.l pool_config.h \ + pool_error.c \ + pool_signal.h pool_signal.c \ + pool_passwd.c pool_passwd.h \ + pool_globals.c -pg_md5_SOURCES = pg_md5.c md5.c md5.h sysconf_DATA = pgpool.conf.sample pcp.conf.sample pool_hba.conf.sample \ - pgpool.conf.sample-replication pgpool.conf.sample-master-slave + pgpool.conf.sample-replication pgpool.conf.sample-master-slave \ + pgpool.conf.sample-stream pkgdata_DATA = sql/system_db.sql sample/pgpool.pam AM_CPPFLAGS = -D_GNU_SOURCE -I @PGSQL_INCLUDE_DIR@ @@ -409,10 +425,12 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pool_config.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pool_connection_pool.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pool_error.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pool_globals.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pool_hba.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pool_ip.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pool_lobj.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pool_params.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pool_passwd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pool_path.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pool_process_context.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pool_process_query.Po@am__quote@ @@ -459,9 +477,7 @@ distclean-compile: @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< .l.c: - $(LEXCOMPILE) $< - sed '/^#/ s|$(LEX_OUTPUT_ROOT)\.c|$@|' $(LEX_OUTPUT_ROOT).c >$@ - rm -f $(LEX_OUTPUT_ROOT).c + $(SHELL) $(YLWRAP) $< $(LEX_OUTPUT_ROOT).c $@ -- $(LEXCOMPILE) mostlyclean-libtool: -rm -f *.lo diff --git a/main.c b/main.c index 7d2452c48..81e97cb49 100644 --- a/main.c +++ b/main.c @@ -49,10 +49,12 @@ #ifdef HAVE_GETOPT_H #include <getopt.h> #endif +#include <libgen.h> #include "version.h" #include "parser/pool_memory.h" #include "parser/pool_string.h" +#include "pool_passwd.h" /* * Process pending signal actions. @@ -141,9 +143,6 @@ static int switching = 0; /* non 0 if I'm fail overing or degenerating */ static int clear_cache = 0; /* non 0 if clear chache option (-c) is given */ static int not_detach = 0; /* non 0 if non detach option (-n) is given */ -int debug = 0; /* non 0 if debug option is given (-d). pcp only */ - -pid_t mypid; /* pgpool parent process id */ long int weight_master; /* normalized weight of master (0-RAND_MAX range) */ @@ -161,7 +160,6 @@ static volatile sig_atomic_t wakeup_request = 0; static int pipe_fds[2]; /* for delivering signals */ int my_proc_id; -bool run_as_pcp_child; static BackendStatusRecord backend_rec; /* Backend status record */ @@ -304,6 +302,18 @@ int main(int argc, char **argv) exit(1); } + /* + * Locate pool_passwd + */ + if (strcmp("", pool_config->pool_passwd)) + { + char pool_passwd[POOLMAXPATHLEN+1]; + + snprintf(pool_passwd, sizeof(pool_passwd), "%s/%s", + dirname(conf_file), pool_config->pool_passwd); + pool_init_pool_passwd(pool_passwd); + } + /* * Override debug level */ diff --git a/md5.c b/md5.c index ee887aa46..827e74cca 100644 --- a/md5.c +++ b/md5.c @@ -24,11 +24,13 @@ #include <stdlib.h> #include <string.h> #include <ctype.h> - +#include "pool.h" #include "md5.h" +#ifdef NOT_USED typedef unsigned char uint8; /* == 8 bits */ typedef unsigned int uint32; /* == 32 bits */ +#endif #define S11 7 #define S12 12 @@ -403,3 +405,40 @@ pool_md5_encrypt(const char *passwd, const char *salt, size_t salt_len, return ret; } + +/* + * Computes MD5 checksum of "passwd" (a null-terminated string) followed + * by "salt" (which need not be null-terminated). + * + * Output format is "md5" followed by a 32-hex-digit MD5 checksum. + * Hence, the output buffer "buf" must be at least 36 bytes long. + * + * Returns TRUE if okay, FALSE on error (out of memory). + */ +bool +pg_md5_encrypt(const char *passwd, const char *salt, size_t salt_len, + char *buf) +{ + size_t passwd_len = strlen(passwd); + + /* +1 here is just to avoid risk of unportable malloc(0) */ + char *crypt_buf = malloc(passwd_len + salt_len + 1); + bool ret; + + if (!crypt_buf) + return false; + + /* + * Place salt at the end because it may be known by users trying to crack + * the MD5 output. + */ + memcpy(crypt_buf, passwd, passwd_len); + memcpy(crypt_buf + passwd_len, salt, salt_len); + + strcpy(buf, "md5"); + ret = pool_md5_hash(crypt_buf, passwd_len + salt_len, buf + 3); + + free(crypt_buf); + + return ret; +} diff --git a/pcp/md5.c b/pcp/md5.c index ee887aa46..827e74cca 100644 --- a/pcp/md5.c +++ b/pcp/md5.c @@ -24,11 +24,13 @@ #include <stdlib.h> #include <string.h> #include <ctype.h> - +#include "pool.h" #include "md5.h" +#ifdef NOT_USED typedef unsigned char uint8; /* == 8 bits */ typedef unsigned int uint32; /* == 32 bits */ +#endif #define S11 7 #define S12 12 @@ -403,3 +405,40 @@ pool_md5_encrypt(const char *passwd, const char *salt, size_t salt_len, return ret; } + +/* + * Computes MD5 checksum of "passwd" (a null-terminated string) followed + * by "salt" (which need not be null-terminated). + * + * Output format is "md5" followed by a 32-hex-digit MD5 checksum. + * Hence, the output buffer "buf" must be at least 36 bytes long. + * + * Returns TRUE if okay, FALSE on error (out of memory). + */ +bool +pg_md5_encrypt(const char *passwd, const char *salt, size_t salt_len, + char *buf) +{ + size_t passwd_len = strlen(passwd); + + /* +1 here is just to avoid risk of unportable malloc(0) */ + char *crypt_buf = malloc(passwd_len + salt_len + 1); + bool ret; + + if (!crypt_buf) + return false; + + /* + * Place salt at the end because it may be known by users trying to crack + * the MD5 output. + */ + memcpy(crypt_buf, passwd, passwd_len); + memcpy(crypt_buf + passwd_len, salt, salt_len); + + strcpy(buf, "md5"); + ret = pool_md5_hash(crypt_buf, passwd_len + salt_len, buf + 3); + + free(crypt_buf); + + return ret; +} diff --git a/pcp_child.c b/pcp_child.c index 3d8f23ac9..508931e5f 100644 --- a/pcp_child.c +++ b/pcp_child.c @@ -65,7 +65,6 @@ static RETSIGTYPE die(int sig); static PCP_CONNECTION *pcp_do_accept(int unix_fd, int inet_fd); static void unset_nonblock(int fd); static int user_authenticate(char *buf, char *passwd_file, char *salt, int salt_len); -static void pool_random_salt(char *md5Salt); static RETSIGTYPE wakeup_handler(int sig); static RETSIGTYPE reload_config_handler(int sig); @@ -1052,22 +1051,6 @@ user_authenticate(char *buf, char *passwd_file, char *salt, int salt_len) return 0; } -/* - * pool_random_salt - */ -static void pool_random_salt(char *md5Salt) -{ - long rand = random(); - - md5Salt[0] = (rand % 255) + 1; - rand = random(); - md5Salt[1] = (rand % 255) + 1; - rand = random(); - md5Salt[2] = (rand % 255) + 1; - rand = random(); - md5Salt[3] = (rand % 255) + 1; -} - /* SIGHUP handler */ static RETSIGTYPE reload_config_handler(int sig) { diff --git a/pg_md5.c b/pg_md5.c index b71f25713..3e88aab44 100644 --- a/pg_md5.c +++ b/pg_md5.c @@ -23,6 +23,7 @@ */ #include "pool.h" #include "pool_config.h" +#include "pool_passwd.h" #include "md5.h" #include <stdio.h> @@ -34,6 +35,8 @@ #ifdef HAVE_GETOPT_H #include <getopt.h> #endif +#include <pwd.h> +#include <libgen.h> /* Maximum number of characters allowed for input. */ #define MAX_INPUT_SIZE 32 @@ -46,6 +49,8 @@ main(int argc, char *argv[]) { #define PRINT_USAGE(exit_code) print_usage(argv[0], exit_code) + char conf_file[POOLMAXPATHLEN+1]; + char pool_passwd[POOLMAXPATHLEN+1]; int opt; int optindex; bool md5auth = false; @@ -55,10 +60,14 @@ main(int argc, char *argv[]) {"help", no_argument, NULL, 'h'}, {"prompt", no_argument, NULL, 'p'}, {"md5auth", no_argument, NULL, 'm'}, + {"md5auth", no_argument, NULL, 'm'}, + {"config-file", required_argument, NULL, 'f'}, {NULL, 0, NULL, 0} }; - while ((opt = getopt_long(argc, argv, "h:p:m", long_options, &optindex)) != -1) + snprintf(conf_file, sizeof(conf_file), "%s/%s", DEFAULT_CONFIGDIR, POOL_CONF_FILE_NAME); + + while ((opt = getopt_long(argc, argv, "hpmf:", long_options, &optindex)) != -1) { switch (opt) { @@ -70,6 +79,14 @@ main(int argc, char *argv[]) md5auth = true; break; + case 'f': /* specify configuration file */ + if (!optarg) + { + PRINT_USAGE(EXIT_SUCCESS); + } + strncpy(conf_file, optarg, sizeof(conf_file)); + break; + default: PRINT_USAGE(EXIT_SUCCESS); break; @@ -104,14 +121,35 @@ main(int argc, char *argv[]) len--; } - pool_md5_hash(buf, len, md5); + if (md5auth) + { + struct passwd *pw; + + if (pool_init_config()) + { + fprintf(stderr, "pool_init_config() failed\n\n"); + PRINT_USAGE(EXIT_FAILURE); + } + + pw = getpwuid(geteuid()); + if (!pw) + { + fprintf(stderr, "getpwuid() failed\n\n"); + exit(EXIT_FAILURE); + } + pool_md5_encrypt(buf, pw->pw_name, strlen(pw->pw_name), md5); + } + else + { + pool_md5_hash(buf, len, md5); + } printf("\n%s\n", md5); } /* Read password from argv. */ else { - char md5[MD5_PASSWD_LEN+1]; + char md5[POOL_PASSWD_LEN+1]; int len; if (optind >= argc) @@ -127,7 +165,41 @@ main(int argc, char *argv[]) PRINT_USAGE(EXIT_FAILURE); } - pool_md5_hash(argv[optind], len, md5); + if (md5auth) + { + struct passwd *pw; + + if (pool_init_config()) + { + fprintf(stderr, "pool_init_config() failed\n\n"); + PRINT_USAGE(EXIT_FAILURE); + } + if (pool_get_config(conf_file, INIT_CONFIG)) + { + fprintf(stderr, "Unable to get configuration. Exiting..."); + PRINT_USAGE(EXIT_FAILURE); + } + + snprintf(pool_passwd, sizeof(pool_passwd), "%s/%s", + dirname(conf_file), pool_config->pool_passwd); + pool_init_pool_passwd(pool_passwd); + + pw = getpwuid(geteuid()); + if (!pw) + { + fprintf(stderr, "getpwuid() failed\n\n"); + exit(EXIT_FAILURE); + } + pg_md5_encrypt(argv[optind], pw->pw_name, strlen(pw->pw_name), md5); + pool_create_passwdent(pw->pw_name, md5); + fprintf(stderr, "%s\n", pool_get_passwd(pw->pw_name)); + pool_finish_pool_passwd(); + } + else + { + pool_md5_hash(argv[optind], len, md5); + } + printf("%s\n", md5); } diff --git a/pool.h b/pool.h index 564c0dd57..835ec628f 100644 --- a/pool.h +++ b/pool.h @@ -562,10 +562,16 @@ extern POOL_STATUS do_query(POOL_CONNECTION *backend, char *query, POOL_SELECT_R extern void free_select_result(POOL_SELECT_RESULT *result); extern int compare(const void *p1, const void *p2); +/* pool_auth.c */ +extern void pool_random_salt(char *md5Salt); + /* main.c */ extern void pool_sleep(unsigned int second); /* pool_worker_child.c */ void do_worker_child(void); +/* md5.c */ +bool pg_md5_encrypt(const char *passwd, const char *salt, size_t salt_len, char *buf); + #endif /* POOL_H */ diff --git a/pool_auth.c b/pool_auth.c index 3bd16196b..e067c233a 100644 --- a/pool_auth.c +++ b/pool_auth.c @@ -25,6 +25,7 @@ #include "pool.h" #include "pool_stream.h" #include "pool_config.h" +#include "pool_passwd.h" #ifdef HAVE_SYS_TYPES_H #include <sys/types.h> @@ -41,15 +42,20 @@ #define AUTHFAIL_ERRORCODE "28000" -static POOL_STATUS pool_send_auth_ok(POOL_CONNECTION *frontend, int pid, int key, int protoMajor); +static POOL_STATUS pool_send_backend_key_data(POOL_CONNECTION *frontend, int pid, int key, int protoMajor); static int do_clear_text_password(POOL_CONNECTION *backend, POOL_CONNECTION *frontend, int reauth, int protoMajor); static void pool_send_auth_fail(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *cp); static int do_crypt(POOL_CONNECTION *backend, POOL_CONNECTION *frontend, int reauth, int protoMajor); static int do_md5(POOL_CONNECTION *backend, POOL_CONNECTION *frontend, int reauth, int protoMajor); - +static int send_md5auth_request(POOL_CONNECTION *frontend, int protoMajor, char *salt); +static int read_password_packet(POOL_CONNECTION *frontend, int protoMajor, char *password); +static int send_password_packet(POOL_CONNECTION *backend, int protoMajor, char *password); +static int send_auth_ok(POOL_CONNECTION *frontend, int protoMajor); /* -* do authentication against backend. if success return 0 otherwise non 0. + * After sending the start up packet to the backend, do the + * authentication against backend. if success return 0 otherwise non + * 0. */ int pool_do_auth(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *cp) { @@ -111,7 +117,7 @@ from pool_read_message_length and recheck the pg_hba.conf settings."); * 5: md5 password * 6: scm credential * - * in replication mode, we only support kind = 0, 3. this is because to "salt" + * in replication mode, we only support kind = 0, 3. this is because "salt" * cannot be replicated. * in non replication mode, we support kind = 0, 3, 4, 5 */ @@ -191,7 +197,10 @@ from pool_read_message_length and recheck the pg_hba.conf settings."); /* md5 authentication? */ else if (authkind == 5) { - if (!RAW_MODE && NUM_BACKENDS > 1) + /* If MD5 auth is not active in pool_hba.conf, it cannot be + * used with other than raw mode. + */ + if (frontend->auth_method != uaMD5 && !RAW_MODE && NUM_BACKENDS > 1) { pool_send_error_message(frontend, protoMajor, AUTHFAIL_ERRORCODE, "MD5 authentication is unsupported in replication, master-slave and parallel modes.", @@ -356,7 +365,7 @@ from pool_read_message_length and recheck the pg_hba.conf settings."); strncpy(cp->info->user, sp->user, sizeof(cp->info->user) - 1); cp->info->counter = 1; - return pool_send_auth_ok(frontend, pid, key, protoMajor); + return pool_send_backend_key_data(frontend, pid, key, protoMajor); } /* @@ -422,7 +431,7 @@ int pool_do_reauth(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *cp) return -1; } - return (pool_send_auth_ok(frontend, MASTER_CONNECTION(cp)->pid, MASTER_CONNECTION(cp)->key, protoMajor) != POOL_CONTINUE); + return (pool_send_backend_key_data(frontend, MASTER_CONNECTION(cp)->pid, MASTER_CONNECTION(cp)->key, protoMajor) != POOL_CONTINUE); } /* @@ -454,28 +463,14 @@ static void pool_send_auth_fail(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL } /* -* send authentication ok to frontend. if success return 0 otherwise non 0. +* Send backend key data to frontend. if success return 0 otherwise non 0. */ -static POOL_STATUS pool_send_auth_ok(POOL_CONNECTION *frontend, int pid, int key, int protoMajor) +static POOL_STATUS pool_send_backend_key_data(POOL_CONNECTION *frontend, int pid, int key, int protoMajor) { char kind; int len; -#ifdef NOT_USED - if (protoMajor == PROTO_MAJOR_V2) - { - /* return "Authentication OK" to the frontend */ - kind = 'R'; - pool_write(frontend, &kind, 1); - len = htonl(0); - if (pool_write_and_flush(frontend, &len, sizeof(len)) < 0) - { - return -1; - } - } -#endif - - /* send backend key data */ + /* Send backend key data */ kind = 'K'; pool_write(frontend, &kind, 1); if (protoMajor == PROTO_MAJOR_V3) @@ -822,78 +817,123 @@ static int do_md5(POOL_CONNECTION *backend, POOL_CONNECTION *frontend, int reaut char salt[4]; static int size; static char password[MAX_PASSWORD_SIZE]; - char response; int kind; - int len; + char encbuf[POOL_PASSWD_LEN+1]; + char *pool_passwd; - if (!reauth) + if (!RAW_MODE && NUM_BACKENDS > 1) { - /* read salt */ - if (pool_read(backend, salt, sizeof(salt))) + /* master? */ + if (IS_MASTER_NODE_ID(backend->db_node_id)) { - pool_error("do_md5: failed to read salt"); - return -1; - } - pool_debug("DB node id: %d salt: %hhx%hhx%hhx%hhx", backend->db_node_id, - salt[0], salt[1], salt[2], salt[3]); - } - else - { - memcpy(salt, backend->salt, sizeof(salt)); - } + /* Send md5 auth request to frontend with my own salt */ + pool_random_salt(salt); + if (send_md5auth_request(frontend, protoMajor, salt)) + { + pool_error("do_md5: send_md5auth_request failed"); + return -1; + } - /* master? */ - if (IS_MASTER_NODE_ID(backend->db_node_id)) - { - pool_write(frontend, "R", 1); /* authenticaton */ - if (protoMajor == PROTO_MAJOR_V3) - { - len = htonl(12); - pool_write(frontend, &len, sizeof(len)); - } - kind = htonl(5); - pool_write(frontend, &kind, sizeof(kind)); /* indicating MD5 */ - pool_write_and_flush(frontend, salt, sizeof(salt)); /* salt */ + /* Read password packet */ + if (read_password_packet(frontend, protoMajor, password)) + { + pool_error("do_md5: read_password_packet failed"); + return -1; + } - /* read password packet */ - if (protoMajor == PROTO_MAJOR_V2) - { - if (pool_read(frontend, &size, sizeof(size))) + /* Check the password using my salt + pool_passwd */ + pool_passwd = pool_get_passwd(frontend->username); + if (!pool_passwd) { - pool_error("do_md5: failed to read password packet size"); + pool_debug("do_md5: %s does not exist in pool_passwd", frontend->username); + return -1; + } + + pg_md5_encrypt(pool_passwd+strlen("md5"), salt, sizeof(salt), encbuf); + if (strcmp(password, encbuf)) + { + /* Password does not match */ + pool_debug("password does not match: frontend:%s pgpool:%s", password, encbuf); return -1; } } - else - { - char k; + kind = 0; - if (pool_read(frontend, &k, sizeof(k))) + if (!reauth) + { + /* + * If ok, authenticate against backends using pool_passwd + */ + /* Read salt */ + if (pool_read(backend, salt, sizeof(salt))) { - pool_debug("do_md5_password: failed to read password packet \"p\""); + pool_error("do_md5: failed to read salt"); return -1; } - if (k != 'p') + pool_debug("DB node id: %d salt: %hhx%hhx%hhx%hhx", backend->db_node_id, + salt[0], salt[1], salt[2], salt[3]); + + /* Encrypt password in pool_passwd using the salt */ + pg_md5_encrypt(pool_passwd+strlen("md5"), salt, sizeof(salt), encbuf); + + /* Send password packet to backend and receive auth response */ + kind = send_password_packet(backend, protoMajor, encbuf); + if (kind < 0) { - pool_error("do_md5_password: password packet does not start with \"p\""); return -1; } - if (pool_read(frontend, &size, sizeof(size))) + } + + if (!reauth && kind == 0) + { + if (IS_MASTER_NODE_ID(backend->db_node_id)) + { + /* Send auth ok to frontend */ + if (send_auth_ok(frontend, protoMajor) < 0) + { + pool_error("do_md5: send_auth_ok failed"); + return -1; + } + } + + /* Save the auth info */ + backend->auth_kind = 5; + } + return kind; + } + else + { + if (!reauth) + { + /* read salt */ + if (pool_read(backend, salt, sizeof(salt))) { - pool_error("do_md5_password: failed to read password packet size"); + pool_error("do_md5: failed to read salt"); return -1; } + pool_debug("DB node id: %d salt: %hhx%hhx%hhx%hhx", backend->db_node_id, + salt[0], salt[1], salt[2], salt[3]); + } + else + { + memcpy(salt, backend->salt, sizeof(salt)); } + } - if ((ntohl(size) - 4) > sizeof(password)) + /* master? */ + if (IS_MASTER_NODE_ID(backend->db_node_id)) + { + /* Send md5 auth request to frontend */ + if (send_md5auth_request(frontend, protoMajor, salt)) { - pool_error("do_md5: password is too long(size: %d)", ntohl(size) - 4); + pool_error("do_md5: send_md5auth_request failed"); return -1; } - if (pool_read(frontend, password, ntohl(size) - 4)) + /* Read password packet */ + if (read_password_packet(frontend, protoMajor, password)) { - pool_error("do_md5: failed to read password (size: %d)", ntohl(size) - 4); + pool_error("do_md5: read_password_packet failed"); return -1; } } @@ -916,20 +956,124 @@ static int do_md5(POOL_CONNECTION *backend, POOL_CONNECTION *frontend, int reaut return 0; } - /* send password packet to backend */ + /* Send password packet to backend and receive auth response */ + kind = send_password_packet(backend, protoMajor, password); + if (kind < 0) + { + return -1; + } + + /* If authenticated, reply back to frontend and save info */ + if (!reauth && kind == 0) + { + if (send_auth_ok(frontend, protoMajor) < 0) + { + pool_error("do_md5: send_auth_ok failed"); + return -1; + } + + backend->auth_kind = 5; + backend->pwd_size = ntohl(size) - 4; + memcpy(backend->password, password, backend->pwd_size); + memcpy(backend->salt, salt, sizeof(salt)); + } + return kind; +} + +/* + * Send md5 authentication request packet to frontend + */ +static int send_md5auth_request(POOL_CONNECTION *frontend, int protoMajor, char *salt) +{ + int len; + int kind; + + pool_write(frontend, "R", 1); /* authenticaton */ + if (protoMajor == PROTO_MAJOR_V3) + { + len = htonl(12); + pool_write(frontend, &len, sizeof(len)); + } + kind = htonl(5); + pool_write(frontend, &kind, sizeof(kind)); /* indicating MD5 */ + pool_write_and_flush(frontend, salt, 4); /* salt */ + + return 0; +} + +/* + * Read password packet from frontend + */ +static int read_password_packet(POOL_CONNECTION *frontend, int protoMajor, char *password) +{ + int size; + + /* Read password packet */ + if (protoMajor == PROTO_MAJOR_V2) + { + if (pool_read(frontend, &size, sizeof(size))) + { + pool_error("read_password_packet: failed to read password packet size"); + return -1; + } + } + else + { + char k; + + if (pool_read(frontend, &k, sizeof(k))) + { + pool_debug("read_password_packet_password: failed to read password packet \"p\""); + return -1; + } + if (k != 'p') + { + pool_error("read_password_packet_password: password packet does not start with \"p\""); + return -1; + } + if (pool_read(frontend, &size, sizeof(size))) + { + pool_error("read_password_packet_password: failed to read password packet size"); + return -1; + } + } + + if (pool_read(frontend, password, ntohl(size) - 4)) + { + pool_error("read_password_packet: failed to read password (size: %d)", ntohl(size) - 4); + return -1; + } + return 0; +} + +/* + * Send password packet to backend and receive authentication response + * packet. Return value is the last field of authentication + * response. If it's 0, authentication was successfull. + */ +static int send_password_packet(POOL_CONNECTION *backend, int protoMajor, char *password) +{ + int size; + int len; + int kind; + char response; + + /* Send password packet to backend */ if (protoMajor == PROTO_MAJOR_V3) pool_write(backend, "p", 1); + size = htonl(sizeof(size) + strlen(password)); pool_write(backend, &size, sizeof(size)); - pool_write_and_flush(backend, password, ntohl(size) -4); + pool_write_and_flush(backend, password, strlen(password)); + if (pool_read(backend, &response, sizeof(response))) { - pool_error("do_md5: failed to read authentication response"); + pool_error("send_password_packet: failed to read authentication response"); return -1; } if (response != 'R') { - pool_debug("do_md5: backend does not return R while processing MD5 authentication %c", response); + pool_debug("send_password_packet: backend does not return R"); return -1; } @@ -937,49 +1081,48 @@ static int do_md5(POOL_CONNECTION *backend, POOL_CONNECTION *frontend, int reaut { if (pool_read(backend, &len, sizeof(len))) { - pool_error("do_md5: failed to read authentication packet size"); + pool_error("send_password_packet: failed to read authentication packet size"); return -1; } if (ntohl(len) != 8) { - pool_error("do_md5: incorrect authentication packet size (%d)", ntohl(len)); + pool_error("send_password_packet: incorrect authentication packet size (%d)", ntohl(len)); return -1; } } - /* expect to read "Authentication OK" response. kind should be 0... */ + /* Expect to read "Authentication OK" response. kind should be 0... */ if (pool_read(backend, &kind, sizeof(kind))) { - pool_debug("do_md5: failed to read Authentication OK response"); + pool_debug("send_password_packet: failed to read Authentication OK response"); return -1; } - /* if authenticated, save info */ - if (!reauth && kind == 0) - { - int msglen; + return kind; +} - pool_write(frontend, "R", 1); +/* + * Send auth ok to frontend + */ +static int send_auth_ok(POOL_CONNECTION *frontend, int protoMajor) +{ + int msglen; - if (protoMajor == PROTO_MAJOR_V3) - { - msglen = htonl(8); - pool_write(frontend, &msglen, sizeof(msglen)); - } + pool_write(frontend, "R", 1); - msglen = htonl(0); - if (pool_write_and_flush(frontend, &msglen, sizeof(msglen)) < 0) - { - return -1; - } + if (protoMajor == PROTO_MAJOR_V3) + { + msglen = htonl(8); + pool_write(frontend, &msglen, sizeof(msglen)); + } - backend->auth_kind = 5; - backend->pwd_size = ntohl(size) - 4; - memcpy(backend->password, password, backend->pwd_size); - memcpy(backend->salt, salt, sizeof(salt)); + msglen = htonl(0); + if (pool_write_and_flush(frontend, &msglen, sizeof(msglen)) < 0) + { + return -1; } - return kind; + return 0; } /* @@ -1168,3 +1311,19 @@ int pool_read_int(POOL_CONNECTION_POOL *cp) return data; } + +/* + * pool_random_salt + */ +void pool_random_salt(char *md5Salt) +{ + long rand = random(); + + md5Salt[0] = (rand % 255) + 1; + rand = random(); + md5Salt[1] = (rand % 255) + 1; + rand = random(); + md5Salt[2] = (rand % 255) + 1; + rand = random(); + md5Salt[3] = (rand % 255) + 1; +} diff --git a/pool_config.c b/pool_config.c index 5daca5d14..e8b16950f 100644 --- a/pool_config.c +++ b/pool_config.c @@ -1838,12 +1838,21 @@ int pool_init_config(void) memset(pool_config, 0, sizeof(POOL_CONFIG)); +#ifdef PGPOOL_MAIN pool_config->backend_desc = pool_shared_memory_create(sizeof(BackendDesc)); if (pool_config->backend_desc == NULL) { pool_error("failed to allocate pool_config->backend_desc"); return -1; } +#else + pool_config->backend_desc = malloc(sizeof(BackendDesc)); + if (pool_config->backend_desc == NULL) + { + pool_error("failed to allocate pool_config->backend_desc"); + return -1; + } +#endif /* set hardcoded default values */ pool_config->listen_addresses = "localhost"; @@ -1867,6 +1876,7 @@ int pool_init_config(void) pool_config->log_connections = 0; pool_config->log_hostname = 0; pool_config->enable_pool_hba = 0; + pool_config->pool_passwd = "pool_passwd"; pool_config->replication_mode = 0; pool_config->load_balance_mode = 0; @@ -2250,6 +2260,25 @@ int pool_get_config(char *confpath, POOL_CONFIG_CONTEXT context) } pool_config->enable_pool_hba = v; } + else if (!strcmp(key, "pool_passwd") && CHECK_CONTEXT(INIT_CONFIG, context)) + { + char *str; + + if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY) + { + PARSE_ERROR(); + fclose(fd); + return(-1); + } + str = extract_string(yytext, token); + if (str == NULL) + { + fclose(fd); + return(-1); + } + pool_config->pool_passwd = str; + } + else if (!strcmp(key, "backend_socket_dir") && CHECK_CONTEXT(INIT_CONFIG, context)) { char *str; @@ -3188,12 +3217,17 @@ int pool_get_config(char *confpath, POOL_CONFIG_CONTEXT context) } memset(system_db_info, 0, sizeof(*system_db_info)); +#ifdef PGPOOL_MAIN system_db_info->system_db_status = pool_shared_memory_create(sizeof(BACKEND_STATUS)); +#else + system_db_info->system_db_status = malloc(sizeof(BACKEND_STATUS)); +#endif if (system_db_info->system_db_status == NULL) { pool_error("failed to allocate system_db_info->system_db_status"); return -1; } + *system_db_info->system_db_status = CON_CONNECT_WAIT; /* which is the same as SYSDB_STATUS = CON_CONNECT_WAIT */ info = malloc(sizeof(SystemDBInfo)); @@ -3213,8 +3247,10 @@ int pool_get_config(char *confpath, POOL_CONFIG_CONTEXT context) info->dist_def_num = 0; info->dist_def_slot = NULL; +#ifdef PGPOOL_MAIN if (pool_config->parallel_mode) { + dist_num = pool_memset_system_db_info(info); if(dist_num < 0) { @@ -3237,6 +3273,7 @@ int pool_get_config(char *confpath, POOL_CONFIG_CONTEXT context) } } SYSDB_STATUS = CON_UP; +#endif } return 0; diff --git a/pool_config.h b/pool_config.h index 92fbeb714..3f0d65543 100644 --- a/pool_config.h +++ b/pool_config.h @@ -58,6 +58,7 @@ typedef struct { int log_connections; /* 0:false, 1:true - logs incoming connections */ int log_hostname; /* 0:false, 1:true - resolve hostname */ int enable_pool_hba; /* 0:false, 1:true - enables pool_hba.conf file authentication */ + char *pool_passwd; /* pool_passwd file name. "" disables pool_passwd */ int load_balance_mode; /* load balance mode */ diff --git a/pool_config.l b/pool_config.l index 972e3230b..d76e0a355 100644 --- a/pool_config.l +++ b/pool_config.l @@ -113,12 +113,21 @@ int pool_init_config(void) memset(pool_config, 0, sizeof(POOL_CONFIG)); +#ifdef PGPOOL_MAIN pool_config->backend_desc = pool_shared_memory_create(sizeof(BackendDesc)); if (pool_config->backend_desc == NULL) { pool_error("failed to allocate pool_config->backend_desc"); return -1; } +#else + pool_config->backend_desc = malloc(sizeof(BackendDesc)); + if (pool_config->backend_desc == NULL) + { + pool_error("failed to allocate pool_config->backend_desc"); + return -1; + } +#endif /* set hardcoded default values */ pool_config->listen_addresses = "localhost"; @@ -142,6 +151,7 @@ int pool_init_config(void) pool_config->log_connections = 0; pool_config->log_hostname = 0; pool_config->enable_pool_hba = 0; + pool_config->pool_passwd = "pool_passwd"; pool_config->replication_mode = 0; pool_config->load_balance_mode = 0; @@ -525,6 +535,25 @@ int pool_get_config(char *confpath, POOL_CONFIG_CONTEXT context) } pool_config->enable_pool_hba = v; } + else if (!strcmp(key, "pool_passwd") && CHECK_CONTEXT(INIT_CONFIG, context)) + { + char *str; + + if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY) + { + PARSE_ERROR(); + fclose(fd); + return(-1); + } + str = extract_string(yytext, token); + if (str == NULL) + { + fclose(fd); + return(-1); + } + pool_config->pool_passwd = str; + } + else if (!strcmp(key, "backend_socket_dir") && CHECK_CONTEXT(INIT_CONFIG, context)) { char *str; @@ -1463,12 +1492,17 @@ int pool_get_config(char *confpath, POOL_CONFIG_CONTEXT context) } memset(system_db_info, 0, sizeof(*system_db_info)); +#ifdef PGPOOL_MAIN system_db_info->system_db_status = pool_shared_memory_create(sizeof(BACKEND_STATUS)); +#else + system_db_info->system_db_status = malloc(sizeof(BACKEND_STATUS)); +#endif if (system_db_info->system_db_status == NULL) { pool_error("failed to allocate system_db_info->system_db_status"); return -1; } + *system_db_info->system_db_status = CON_CONNECT_WAIT; /* which is the same as SYSDB_STATUS = CON_CONNECT_WAIT */ info = malloc(sizeof(SystemDBInfo)); @@ -1488,8 +1522,10 @@ int pool_get_config(char *confpath, POOL_CONFIG_CONTEXT context) info->dist_def_num = 0; info->dist_def_slot = NULL; +#ifdef PGPOOL_MAIN if (pool_config->parallel_mode) { + dist_num = pool_memset_system_db_info(info); if(dist_num < 0) { @@ -1512,6 +1548,7 @@ int pool_get_config(char *confpath, POOL_CONFIG_CONTEXT context) } } SYSDB_STATUS = CON_UP; +#endif } return 0; diff --git a/pool_globals.c b/pool_globals.c new file mode 100644 index 000000000..2ff50f7a3 --- /dev/null +++ b/pool_globals.c @@ -0,0 +1,27 @@ +/* -*-pgsql-c-*- */ +/* + * $Header$ + * + * pgpool: a language independent connection pool server for PostgreSQL + * written by Tatsuo Ishii + * + * Copyright (c) 2003-2010 PgPool Global Development Group + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that the above copyright notice appear in all + * copies and that both that copyright notice and this permission + * notice appear in supporting documentation, and that the name of the + * author not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. The author makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * Global varibles. Should be eventually removed. + */ +#include "pool.h" + +int debug = 0; /* non 0 if debug option is given (-d). pcp only */ +pid_t mypid; /* pgpool parent process id */ +bool run_as_pcp_child; diff --git a/pool_hba.c b/pool_hba.c index 16e23e8a8..909c6c9ea 100644 --- a/pool_hba.c +++ b/pool_hba.c @@ -62,6 +62,7 @@ static char *tokenize_inc_file(const char *outer_filename, const char *inc_filen static bool pg_isblank(const char c); static void next_token(FILE *fp, char *buf, int bufsz); static char * next_token_expand(const char *filename, FILE *file); +static POOL_STATUS CheckMd5Auth(POOL_CONNECTION *frontend); #ifdef USE_PAM #ifdef HAVE_PAM_PAM_APPL_H @@ -217,8 +218,9 @@ void ClientAuthentication(POOL_CONNECTION *frontend) /* case uaIdent: */ /* break; */ -/* case uaMD5: */ -/* break; */ + case uaMD5: + status = CheckMd5Auth(frontend); + break; /* case uaCrypt: */ /* break; */ @@ -389,7 +391,12 @@ static void auth_failed(POOL_CONNECTION *frontend) /* "Ident authentication with pgpool failed for user \"%s\"", */ /* frontend->username); */ /* break; */ -/* case uaMD5: */ + case uaMD5: + snprintf(errmessage, messagelen, + "\"MD5\" authentication with pgpool failed for user \"%s\"", + frontend->username); + break; + /* case uaCrypt: */ /* case uaPassword: */ /* snprintf(errmessage, messagelen, */ @@ -793,9 +800,9 @@ static void parse_hba_auth(ListCell **line_item, UserAuth *userauth_p, */ else if (strcmp(token, "reject") == 0) *userauth_p = uaReject; - /* else if (strcmp(token, "md5") == 0) *userauth_p = uaMD5; + /* else if (strcmp(token, "crypt") == 0) *userauth_p = uaCrypt; */ @@ -1436,3 +1443,19 @@ static POOL_STATUS CheckPAMAuth(POOL_CONNECTION *frontend, char *user, char *pas } #endif /* USE_PAM */ + +static POOL_STATUS CheckMd5Auth(POOL_CONNECTION *frontend) +{ + POOL_STATUS status; + + /* Look for the entry in pool_passwd */ + + /* Not found. authentication failed */ + /* return POOL_ERROR;*/ + + /* + * If found, save the password. + * Actual authentication will be performed later. + */ + return POOL_CONTINUE; +} diff --git a/pool_type.h b/pool_type.h index 368d3b4af..80571df11 100644 --- a/pool_type.h +++ b/pool_type.h @@ -254,11 +254,11 @@ typedef enum UserAuth uaReject, /* uaKrb4, */ /* uaKrb5, */ - uaTrust + uaTrust, /* uaIdent, */ /* uaPassword, */ /* uaCrypt, */ - /* uaMD5 */ + uaMD5 #ifdef USE_PAM ,uaPAM #endif /* USE_PAM */ [parent: cf0799d7d24a]