From 3a7c93e7f32b555defdc2ea0b0554f6dd0a34c41 Mon Sep 17 00:00:00 2001 From: "Marc G. Fournier" Date: Wed, 12 Mar 1997 21:23:16 +0000 Subject: [PATCH] From: Dan McGuirk Subject: [HACKERS] password authentication This patch adds support for plaintext password authentication. To use it, you add a line like host all 0.0.0.0 0.0.0.0 password pg_pwd.conf to your pg_hba.conf, where 'pg_pwd.conf' is the name of a file containing the usernames and password hashes in the format of the first two fields of a Unix /etc/passwd file. (Of course, you can use a specific database name or IP instead.) Then, to connect with a password through libpq, you use the PQconnectdb() function, specifying the "password=" tag in the connect string and also adding the tag "authtype=password". I also added a command-line switch '-u' to psql that tells it to prompt for a username and password and use password authentication. --- src/backend/libpq/Makefile | 5 +- src/backend/libpq/auth.c | 47 +++++++++-- src/backend/libpq/hba.c | 100 +++++++++++------------ src/backend/libpq/pqcomm.c | 28 ++++++- src/backend/postmaster/postmaster.c | 6 +- src/bin/psql/psql.c | 120 +++++++++++++++++++++++++++- src/include/config.h.in | 7 +- src/include/libpq/hba.h | 32 +++++++- src/include/libpq/pqcomm.h | 11 ++- src/interfaces/libpq/fe-auth.c | 28 ++++++- src/interfaces/libpq/fe-auth.h | 6 +- src/interfaces/libpq/fe-connect.c | 36 ++++++++- src/interfaces/libpq/libpq-fe.h | 4 +- 13 files changed, 345 insertions(+), 85 deletions(-) diff --git a/src/backend/libpq/Makefile b/src/backend/libpq/Makefile index c8a0533a2b..a7c7f13704 100644 --- a/src/backend/libpq/Makefile +++ b/src/backend/libpq/Makefile @@ -4,7 +4,7 @@ # Makefile for libpq subsystem (backend half of libpq interface) # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/backend/libpq/Makefile,v 1.4 1996/11/14 10:23:51 bryanh Exp $ +# $Header: /cvsroot/pgsql/src/backend/libpq/Makefile,v 1.5 1997/03/12 21:17:45 scrappy Exp $ # #------------------------------------------------------------------------- @@ -24,7 +24,8 @@ LDADD+= $(KRBLIBS) endif OBJS = be-dumpdata.o be-fsstubs.o be-pqexec.o \ - auth.o hba.o pqcomm.o portal.o util.o portalbuf.o pqpacket.o pqsignal.o + auth.o hba.o pqcomm.o portal.o util.o portalbuf.o pqpacket.o pqsignal.o \ + password.o all: SUBSYS.o diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index d1cb560f19..333fb6ce7d 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.8 1996/11/16 08:09:15 bryanh Exp $ + * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.9 1997/03/12 21:17:48 scrappy Exp $ * *------------------------------------------------------------------------- */ @@ -70,6 +70,7 @@ #include #include #include +#include /*---------------------------------------------------------------- * common definitions for generic fe/be routines @@ -113,10 +114,11 @@ static struct authsvc authsvcs[] = { { "krb4", STARTUP_KRB4_MSG, 1 }, { "krb5", STARTUP_KRB5_MSG, 1 }, #if defined(KRB5) - { "kerberos", STARTUP_KRB5_MSG, 1 } + { "kerberos", STARTUP_KRB5_MSG, 1 }, #else - { "kerberos", STARTUP_KRB4_MSG, 1 } + { "kerberos", STARTUP_KRB4_MSG, 1 }, #endif + { "password", STARTUP_PASSWORD_MSG, 1 } }; static n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc); @@ -403,6 +405,26 @@ return(STATUS_ERROR); } #endif /* KRB5 */ +static int +pg_password_recvauth(Port *port, char *database, char *DataDir) +{ + PacketBuf buf; + char *user, *password; + + if(PacketReceive(port, &buf, BLOCKING) != STATUS_OK) { + sprintf(PQerrormsg, + "pg_password_recvauth: failed to receive authentication packet.\n"); + fputs(PQerrormsg, stderr); + pqdebug("%s", PQerrormsg); + return STATUS_ERROR; + } + + user = buf.data; + password = buf.data + strlen(user) + 1; + + return verify_password(user, password, port, database, DataDir); +} + /* * be_recvauth -- server demux routine for incoming authentication information */ @@ -418,8 +440,8 @@ be_recvauth(MsgType msgtype_arg, Port *port, char *username, StartupInfo* sp) */ if (msgtype_arg == STARTUP_MSG && useHostBasedAuth) msgtype = STARTUP_HBA_MSG; - else - msgtype = STARTUP_UNAUTH_MSG; + else + msgtype = msgtype_arg; if (!username) { (void) sprintf(PQerrormsg, @@ -490,6 +512,21 @@ be_recvauth(MsgType msgtype_arg, Port *port, char *username, StartupInfo* sp) return(STATUS_ERROR); } break; + case STARTUP_PASSWORD_MSG: + if(!be_getauthsvc(msgtype)) { + sprintf(PQerrormsg, + "be_recvauth: " + "plaintext password authentication disallowed\n"); + fputs(PQerrormsg, stderr); + pqdebug("%s", PQerrormsg); + return(STATUS_ERROR); + } + if(pg_password_recvauth(port, sp->database, DataDir) != STATUS_OK) { + /* pg_password_recvauth or lower-level routines have already set */ + /* the error message */ + return(STATUS_ERROR); + } + break; default: (void) sprintf(PQerrormsg, "be_recvauth: unrecognized message type: %d\n", diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c index 4bdf497a75..22d532bf53 100644 --- a/src/backend/libpq/hba.c +++ b/src/backend/libpq/hba.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.15 1997/01/14 01:56:44 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.16 1997/03/12 21:17:53 scrappy Exp $ * *------------------------------------------------------------------------- */ @@ -30,31 +30,6 @@ #include /* For inet_aton() */ -#define CONF_FILE "pg_hba.conf" - /* Name of the config file */ - -#define MAP_FILE "pg_ident.conf" - /* Name of the usermap file */ - -#define OLD_CONF_FILE "pg_hba" - /* Name of the config file in prior releases of Postgres. */ - -#define MAX_LINES 255 - /* Maximum number of config lines that can apply to one database */ - -#define MAX_TOKEN 80 -/* Maximum size of one token in the configuration file */ - -#define USERMAP_NAME_SIZE 16 /* Max size of a usermap name */ - -#define IDENT_PORT 113 - /* Standard TCP port number for Ident service. Assigned by IANA */ - -#define IDENT_USERNAME_MAX 512 - /* Max size of username ident server can return */ - -enum Userauth {Trust, Ident}; - /* Some standard C libraries, including GNU, have an isblank() function. Others, including Solaris, do not. So we have our own. */ @@ -108,7 +83,7 @@ read_through_eol(FILE *file) { static void read_hba_entry2(FILE *file, enum Userauth *userauth_p, char usermap_name[], - bool *error_p) { + bool *error_p, bool *matches_p, bool find_password_entries) { /*-------------------------------------------------------------------------- Read from file FILE the rest of a host record, after the mask field, and return the interpretation of it as *userauth_p, usermap_name, and @@ -120,34 +95,47 @@ read_hba_entry2(FILE *file, enum Userauth *userauth_p, char usermap_name[], /* Get authentication type token. */ next_token(file, buf, sizeof(buf)); + userauth_valid = false; if (buf[0] == '\0') { *error_p = true; - read_through_eol(file); } else { - if (strcmp(buf, "trust") == 0) { - userauth_valid = true; + userauth_valid = true; + if(strcmp(buf, "trust") == 0) { *userauth_p = Trust; - } else if (strcmp(buf, "ident") == 0) { - userauth_valid = true; + } else if(strcmp(buf, "ident") == 0) { *userauth_p = Ident; - } else userauth_valid = false; + } else if(strcmp(buf, "password") == 0) { + *userauth_p = Password; + } else { + userauth_valid = false; + } + + if((find_password_entries && strcmp(buf, "password") == 0) || + (!find_password_entries && strcmp(buf, "password") != 0)) { + *matches_p = true; + } else { + *matches_p = false; + } + } + + if(!userauth_valid || !*matches_p || *error_p) { if (!userauth_valid) { *error_p = true; - read_through_eol(file); + } + read_through_eol(file); + } else { + /* Get the map name token, if any */ + next_token(file, buf, sizeof(buf)); + if (buf[0] == '\0') { + *error_p = false; + usermap_name[0] = '\0'; } else { - /* Get the map name token, if any */ + strncpy(usermap_name, buf, USERMAP_NAME_SIZE); next_token(file, buf, sizeof(buf)); - if (buf[0] == '\0') { - *error_p = false; - usermap_name[0] = '\0'; - } else { - strncpy(usermap_name, buf, USERMAP_NAME_SIZE); - next_token(file, buf, sizeof(buf)); - if (buf[0] != '\0') { - *error_p = true; - read_through_eol(file); - } else *error_p = false; - } + if (buf[0] != '\0') { + *error_p = true; + read_through_eol(file); + } else *error_p = false; } } } @@ -158,7 +146,8 @@ static void process_hba_record(FILE *file, const struct in_addr ip_addr, const char database[], bool *matches_p, bool *error_p, - enum Userauth *userauth_p, char usermap_name[] ) { + enum Userauth *userauth_p, char usermap_name[], + bool find_password_entries) { /*--------------------------------------------------------------------------- Process the non-comment record in the config file that is next on the file. See if it applies to a connection to a host with IP address "ip_addr" @@ -221,8 +210,7 @@ process_hba_record(FILE *file, the rest of the info from it. */ read_hba_entry2(file, userauth_p, usermap_name, - error_p); - *matches_p = true; + error_p, matches_p, find_password_entries); if (*error_p) { sprintf(PQerrormsg, "process_hba_record: invalid syntax in " @@ -249,7 +237,7 @@ static void process_open_config_file(FILE *file, const struct in_addr ip_addr, const char database[], bool *host_ok_p, enum Userauth *userauth_p, - char usermap_name[] ) { + char usermap_name[], bool find_password_entries) { /*--------------------------------------------------------------------------- This function does the same thing as find_hba_entry, only with the config file already open on stream descriptor "file". @@ -274,7 +262,8 @@ process_open_config_file(FILE *file, if (c == '#') read_through_eol(file); else { process_hba_record(file, ip_addr, database, - &found_entry, &error, userauth_p, usermap_name); + &found_entry, &error, userauth_p, usermap_name, + find_password_entries); } } } @@ -286,11 +275,11 @@ process_open_config_file(FILE *file, -static void +void find_hba_entry(const char DataDir[], const struct in_addr ip_addr, const char database[], bool *host_ok_p, enum Userauth *userauth_p, - char usermap_name[] ) { + char usermap_name[], bool find_password_entries) { /*-------------------------------------------------------------------------- Read the config file and find an entry that allows connection from host "ip_addr" to database "database". If not found, return @@ -360,7 +349,7 @@ find_hba_entry(const char DataDir[], const struct in_addr ip_addr, pqdebug("%s", PQerrormsg); } else { process_open_config_file(file, ip_addr, database, host_ok_p, userauth_p, - usermap_name); + usermap_name, find_password_entries); fclose(file); } free(conf_file); @@ -731,7 +720,8 @@ hba_recvauth(const Port *port, const char database[], const char user[], find_hba_entry(DataDir, port->raddr.sin_addr, database, - &host_ok, &userauth, usermap_name); + &host_ok, &userauth, usermap_name, + false /* don't find password entries of type 'password' */); if (!host_ok) retvalue = STATUS_ERROR; else { diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index 928bc281b8..6b8ecdac28 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.11 1997/02/14 04:15:29 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.12 1997/03/12 21:17:58 scrappy Exp $ * *------------------------------------------------------------------------- */ @@ -703,3 +703,29 @@ StreamOpen(char *hostName, short portName, Port *port) return(STATUS_OK); } + +static char *authentication_type_name[] = { + 0, 0, 0, 0, 0, 0, 0, + "the default authentication type", + 0, 0, + "Kerberos v4", + "Kerberos v5", + "host-based authentication", + "unauthenication", + "plaintext password authentication" +}; + +char *name_of_authentication_type(int type) +{ + char *result = 0; + + if(type >= 1 && type <= LAST_AUTHENTICATION_TYPE) { + result = authentication_type_name[type]; + } + + if(result == 0) { + result = ""; + } + + return result; +} diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 628d44d7d9..5c749c5f35 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.43 1997/03/02 02:17:32 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.44 1997/03/12 21:18:38 scrappy Exp $ * * NOTES * @@ -660,8 +660,8 @@ ConnStartup(Port *port, int *status, char buffer[200 + sizeof(namebuf)]; sprintf(buffer, "Failed to authenticate client as Postgres user '%s' " - "using authentication scheme %d.", - namebuf, msgType); + "using %s: %s", + namebuf, name_of_authentication_type(msgType), PQerrormsg); strncpy(errormsg, buffer, errormsg_len); *status = STATUS_ERROR; } else { diff --git a/src/bin/psql/psql.c b/src/bin/psql/psql.c index 4330c19fd8..6fd299605b 100644 --- a/src/bin/psql/psql.c +++ b/src/bin/psql/psql.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.57 1997/02/13 08:31:48 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.58 1997/03/12 21:19:14 scrappy Exp $ * *------------------------------------------------------------------------- */ @@ -29,6 +29,9 @@ #ifndef HAVE_STRDUP #include "strdup.h" #endif +#ifdef HAVE_TERMIOS_H +#include +#endif #ifdef HAVE_LIBREADLINE # ifdef HAVE_READLINE_H @@ -67,6 +70,7 @@ typedef struct _psqlSettings { bool singleStep; /* prompt before for each query */ bool singleLineMode; /* query terminated by newline */ bool useReadline;/* use libreadline routines */ + bool getPassword;/* prompt the user for a username and password */ } PsqlSettings; /* declarations for functions in this file */ @@ -78,6 +82,9 @@ handleCopyIn(PGresult * res, const bool mustprompt, FILE * copystream); static int tableList(PsqlSettings * ps, bool deep_tablelist); static int tableDesc(PsqlSettings * ps, char *table); +static void prompt_for_password(char *username, char *password); +static char * make_connect_string(char *host, char *port, char *dbname, + char *username, char *password); char *gets_noreadline(char *prompt, FILE * source); char *gets_readline(char *prompt, FILE * source); @@ -125,6 +132,7 @@ usage(char *progname) fprintf(stderr, "\t -s single step mode (prompts for each query)\n"); fprintf(stderr, "\t -S single line mode (i.e. query terminated by newline)\n"); fprintf(stderr, "\t -t turn off printing of headings and row count\n"); + fprintf(stderr, "\t -u ask for a username and password for authentication\n"); fprintf(stderr, "\t -T html set html3.0 table command options (cf. -H)\n"); fprintf(stderr, "\t -x turn on expanded output (field names on left)\n"); exit(1); @@ -1463,8 +1471,13 @@ main(int argc, char **argv) else settings.useReadline = 1; #endif +#ifdef PSQL_ALWAYS_GET_PASSWORDS + settings.getPassword = 1; +#else + settings.getPassword = 0; +#endif - while ((c = getopt(argc, argv, "Aa:c:d:ef:F:lh:Hnso:p:qStT:x")) != EOF) { + while ((c = getopt(argc, argv, "Aa:c:d:ef:F:lh:Hnso:p:qStT:ux")) != EOF) { switch (c) { case 'A': settings.opt.align = 0; @@ -1523,6 +1536,9 @@ main(int argc, char **argv) case 'T': settings.opt.tableOpt = optarg; break; + case 'u': + settings.getPassword = 1; + break; case 'x': settings.opt.expanded = 1; break; @@ -1538,7 +1554,21 @@ main(int argc, char **argv) if (listDatabases) dbname = "template1"; - settings.db = PQsetdb(host, port, NULL, NULL, dbname); + if(settings.getPassword) { + char username[9]; + char password[9]; + char *connect_string; + + prompt_for_password(username, password); + + /* now use PQconnectdb so we can pass these options */ + connect_string = make_connect_string(host, port, dbname, username, password); + settings.db = PQconnectdb(connect_string); + free(connect_string); + } else { + settings.db = PQsetdb(host, port, NULL, NULL, dbname); + } + dbname = PQdb(settings.db); if (PQstatus(settings.db) == CONNECTION_BAD) { @@ -1711,3 +1741,87 @@ setFout(PsqlSettings * ps, char *fname) } return ps->queryFout; } + +static void prompt_for_password(char *username, char *password) +{ + int length; +#ifdef HAVE_TERMIOS_H + struct termios t_orig, t; +#endif + + printf("Username: "); + fgets(username, 9, stdin); + length = strlen(username); + if(length > 0 && username[length-1] == '\n') username[length-1] = '\0'; + + printf("Password: "); +#ifdef HAVE_TERMIOS_H + tcgetattr(0, &t); + t_orig = t; + t.c_lflag &= ~ECHO; + tcsetattr(0, TCSADRAIN, &t); +#endif + fgets(password, 9, stdin); +#ifdef HAVE_TERMIOS_H + tcsetattr(0, TCSADRAIN, &t_orig); +#endif + + length = strlen(password); + if(length > 0 && password[length-1] == '\n') password[length-1] = '\0'; + + printf("\n\n"); +} + +static char *make_connect_string(char *host, char *port, char *dbname, + char *username, char *password) +{ + int connect_string_len = 0; + char *connect_string; + + if(host) + connect_string_len += 6 + strlen(host); /* 6 == "host=" + " " */ + if(username) + connect_string_len += 6 + strlen(username); /* 6 == "user=" + " " */ + if(password) + connect_string_len += 10 + strlen(password); /* 10 == "password=" + " " */ + if(port) + connect_string_len += 6 + strlen(port); /* 6 == "port=" + " " */ + if(dbname) + connect_string_len += 8 + strlen(dbname); /* 8 == "dbname=" + " " */ + connect_string_len += 18; /* "authtype=password" + null */ + + connect_string = (char *)malloc(connect_string_len); + if(!connect_string) { + return 0; + } + connect_string[0] = '\0'; + if(host) { + strcat(connect_string, "host="); + strcat(connect_string, host); + strcat(connect_string, " "); + } + if(username) { + strcat(connect_string, "user="); + strcat(connect_string, username); + strcat(connect_string, " "); + } + if(password) { + strcat(connect_string, "password="); + strcat(connect_string, password); + strcat(connect_string, " "); + } + if(port) { + strcat(connect_string, "port="); + strcat(connect_string, port); + strcat(connect_string, " "); + } + if(dbname) { + strcat(connect_string, "dbname="); + strcat(connect_string, dbname); + strcat(connect_string, " "); + } + strcat(connect_string, "authtype=password"); + + return connect_string; +} + diff --git a/src/include/config.h.in b/src/include/config.h.in index c0f56a2ac0..99973dde07 100644 --- a/src/include/config.h.in +++ b/src/include/config.h.in @@ -266,8 +266,11 @@ */ /*#define GEQO */ /* backend/optimizer/path/allpaths.c */ - - +/* + * Define this if you want psql to _always_ ask for a username and a password + * for password authentication. + */ +/* #define PSQL_ALWAYS_GET_PASSWORDS */ /* Undocumented "features"? */ #define FASTBUILD /* access/nbtree/nbtsort.c */ diff --git a/src/include/libpq/hba.h b/src/include/libpq/hba.h index c68fefefd8..14847438b0 100644 --- a/src/include/libpq/hba.h +++ b/src/include/libpq/hba.h @@ -4,16 +4,46 @@ * Interface to hba.c * * - * $Id: hba.h,v 1.2 1996/11/06 10:29:58 scrappy Exp $ + * $Id: hba.h,v 1.3 1997/03/12 21:22:16 scrappy Exp $ * *------------------------------------------------------------------------- */ #ifndef HBA_H #define HBA_H +#include + +#define CONF_FILE "pg_hba.conf" + /* Name of the config file */ + +#define MAP_FILE "pg_ident.conf" + /* Name of the usermap file */ + +#define OLD_CONF_FILE "pg_hba" + /* Name of the config file in prior releases of Postgres. */ + +#define MAX_LINES 255 + /* Maximum number of config lines that can apply to one database */ + +#define MAX_TOKEN 80 +/* Maximum size of one token in the configuration file */ + +#define USERMAP_NAME_SIZE 16 /* Max size of a usermap name */ + +#define IDENT_PORT 113 + /* Standard TCP port number for Ident service. Assigned by IANA */ + +#define IDENT_USERNAME_MAX 512 + /* Max size of username ident server can return */ + +enum Userauth {Trust, Ident, Password}; extern int hba_recvauth(const Port *port, const char database[], const char user[], const char DataDir[]); +void find_hba_entry(const char DataDir[], const struct in_addr ip_addr, + const char database[], + bool *host_ok_p, enum Userauth *userauth_p, + char usermap_name[], bool find_password_entries); #endif diff --git a/src/include/libpq/pqcomm.h b/src/include/libpq/pqcomm.h index 0a23d226ce..cc9d941800 100644 --- a/src/include/libpq/pqcomm.h +++ b/src/include/libpq/pqcomm.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: pqcomm.h,v 1.7 1997/02/11 15:37:18 momjian Exp $ + * $Id: pqcomm.h,v 1.8 1997/03/12 21:22:19 scrappy Exp $ * * NOTES * Some of this should move to libpq.h @@ -52,10 +52,15 @@ typedef enum _MsgType { STARTUP_KRB4_MSG=10, /* krb4 session follows startup packet */ STARTUP_KRB5_MSG=11, /* krb5 session follows startup packet */ STARTUP_HBA_MSG=12, /* use host-based authentication */ - STARTUP_UNAUTH_MSG=13 /* use unauthenticated connection */ + STARTUP_UNAUTH_MSG=13, /* use unauthenticated connection */ + STARTUP_PASSWORD_MSG=14 /* use plaintext password authentication */ /* insert new values here -- DO NOT REORDER OR DELETE ENTRIES */ + /* also change LAST_AUTHENTICATION_TYPE below and add to the */ + /* authentication_type_name[] array in pqcomm.c */ } MsgType; +#define LAST_AUTHENTICATION_TYPE 14 + typedef char *Addr; typedef int PacketLen; /* packet length */ @@ -126,6 +131,6 @@ extern int PacketSend(Port *port, PacketBuf *buf, PacketLen len, char nonBlocking); /* extern PacketBuf* StartupInfo2PacketBuf(StartupInfo*); */ /* extern StartupInfo* PacketBuf2StartupInfo(PacketBuf*); */ - +extern char *name_of_authentication_type(int type); #endif /* PQCOMM_H */ diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c index 103e64fdf5..66c2acf9ec 100644 --- a/src/interfaces/libpq/fe-auth.c +++ b/src/interfaces/libpq/fe-auth.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.6 1996/11/03 07:14:30 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.7 1997/03/12 21:23:02 scrappy Exp $ * *------------------------------------------------------------------------- */ @@ -40,6 +40,7 @@ #include "libpq-fe.h" #include "fe-auth.h" +#include "fe-connect.h" /*---------------------------------------------------------------- * common definitions for generic fe/be routines @@ -79,7 +80,8 @@ static struct authsvc authsvcs[] = { #else /* !(KRB4 || KRB5) */ 1 #endif /* !(KRB4 || KRB5) */ - } + }, + { "password", STARTUP_PASSWORD_MSG, 0 } }; static n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc); @@ -431,12 +433,30 @@ pg_krb5_sendauth(const char* PQerrormsg,int sock, #endif /* KRB5 */ +static int +pg_password_sendauth(Port *port, const char *user, const char *password) +{ + PacketBuf buf; + char *tmp; + + buf.len = htonl(sizeof(PacketBuf)); + buf.msgtype = STARTUP_PASSWORD_MSG; + buf.data[0] = '\0'; + + tmp = buf.data; + strncpy(tmp, user, strlen(user)+1); + tmp += strlen(user)+1; + strncpy(tmp, password, strlen(password)+1); + + return packetSend(port, &buf, sizeof(PacketBuf), BLOCKING); +} /* * fe_sendauth -- client demux routine for outgoing authentication information */ int -fe_sendauth(MsgType msgtype, Port *port, const char *hostname, const char* PQerrormsg) +fe_sendauth(MsgType msgtype, Port *port, const char *hostname, + const char *user, const char *password, const char* PQerrormsg) { switch (msgtype) { #ifdef KRB4 @@ -464,6 +484,8 @@ fe_sendauth(MsgType msgtype, Port *port, const char *hostname, const char* PQerr #endif case STARTUP_MSG: break; + case STARTUP_PASSWORD_MSG: + pg_password_sendauth(port, user, password); default: break; } diff --git a/src/interfaces/libpq/fe-auth.h b/src/interfaces/libpq/fe-auth.h index fa939ac122..646f93df37 100644 --- a/src/interfaces/libpq/fe-auth.h +++ b/src/interfaces/libpq/fe-auth.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: fe-auth.h,v 1.2 1996/08/06 16:16:44 scrappy Exp $ + * $Id: fe-auth.h,v 1.3 1997/03/12 21:23:04 scrappy Exp $ * *------------------------------------------------------------------------- */ @@ -28,7 +28,9 @@ #define DEFAULT_CLIENT_AUTHSVC "kerberos" #endif /* KRB4 || KRB5 */ -extern int fe_sendauth(MsgType msgtype, Port *port, const char *hostname, const char* PQerromsg); +extern int fe_sendauth(MsgType msgtype, Port *port, const char *hostname, + const char *user, const char *password, + const char* PQerromsg); extern void fe_setauthsvc(const char *name, char* PQerrormsg); #define PG_KRB4_VERSION "PGVER4.1" /* at most KRB_SENDAUTH_VLEN chars */ diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index cb2d06c0ab..60f55ae599 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.23 1997/02/13 08:32:08 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.24 1997/03/12 21:23:09 scrappy Exp $ * *------------------------------------------------------------------------- */ @@ -28,6 +28,7 @@ #include "postgres.h" #include "libpq/pqcomm.h" /* for decls of MsgType, PacketBuf, StartupInfo */ #include "fe-auth.h" +#include "fe-connect.h" #include "libpq-fe.h" #ifndef HAVE_STRDUP @@ -38,8 +39,6 @@ /* use a local version instead of the one found in pqpacket.c */ static ConnStatusType connectDB(PGconn *conn); -static int packetSend(Port *port, PacketBuf *buf, PacketLen len, - bool nonBlocking); static void startup2PacketBuf(StartupInfo* s, PacketBuf* res); static void freePGconn(PGconn *conn); static void closePGconn(PGconn *conn); @@ -73,9 +72,15 @@ static PQconninfoOption PQconninfoOptions[] = { /* Option-name Environment-Var Compiled-in Current value */ /* Label Disp-Char */ /* ----------------- --------------- --------------- --------------- */ + { "authtype", "PGAUTHTYPE", NULL, NULL, + "Database-Authtype", "", 20 }, + { "user", "PGUSER", NULL, NULL, "Database-User", "", 20 }, + { "password", "PGPASSWORD", NULL, NULL, + "Database-Password", "", 20 }, + { "dbname", "PGDATABASE", NULL, NULL, "Database-Name", "", 20 }, @@ -187,6 +192,8 @@ PQconnectdb(const char *conninfo) conn->pgtty = strdup(conninfo_getval("tty")); conn->pgoptions = strdup(conninfo_getval("options")); conn->pguser = strdup(conninfo_getval("user")); + conn->pgpass = strdup(conninfo_getval("password")); + conn->pgauth = strdup(conninfo_getval("authtype")); conn->dbName = strdup(conninfo_getval("dbname")); /* ---------- @@ -195,6 +202,13 @@ PQconnectdb(const char *conninfo) */ conninfo_free(); + /* + * try to set the auth service if one was specified + */ + if(conn->pgauth) { + fe_setauthsvc(conn->pgauth, conn->errorMessage); + } + /* ---------- * Connect to the database * ---------- @@ -260,6 +274,8 @@ PQconndefaults(void) * * PGUSER Postgres username to associate with the connection. * + * PGPASSWORD The user's password. + * * PGDATABASE name of database to which to connect if * argument is NULL or a null string * @@ -336,6 +352,12 @@ PQsetdb(const char *pghost, const char* pgport, const char* pgoptions, const cha } } + if((tmp = getenv("PGPASSWORD"))) { + conn->pgpass = strdup(tmp); + } else { + conn->pgpass = 0; + } + if (!error) { if (((tmp = (char *)dbName) && (dbName[0] != '\0')) || ((tmp = getenv("PGDATABASE")))) { @@ -467,6 +489,7 @@ connectDB(PGconn *conn) /* authenticate as required*/ if (fe_sendauth(msgtype, port, conn->pghost, + conn->pguser, conn->pgpass, conn->errorMessage) != STATUS_OK) { (void) sprintf(conn->errorMessage, "connectDB() -- authentication failed with %s\n", @@ -474,6 +497,11 @@ connectDB(PGconn *conn) goto connect_errReturn; } + /* free the password so it's not hanging out in memory forever */ + if(conn->pgpass) { + free(conn->pgpass); + } + /* set up the socket file descriptors */ conn->Pfout = fdopen(port->sock, "w"); conn->Pfin = fdopen(dup(port->sock), "r"); @@ -595,7 +623,7 @@ PQreset(PGconn *conn) * buffer management. For now, we're not going to do it. * */ -static int +int packetSend(Port *port, PacketBuf *buf, PacketLen len, diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h index 8d9182ac3e..c765661e71 100644 --- a/src/interfaces/libpq/libpq-fe.h +++ b/src/interfaces/libpq/libpq-fe.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: libpq-fe.h,v 1.17 1997/01/06 10:11:11 bryanh Exp $ + * $Id: libpq-fe.h,v 1.18 1997/03/12 21:23:16 scrappy Exp $ * *------------------------------------------------------------------------- */ @@ -125,6 +125,8 @@ typedef struct pg_conn{ int asyncNotifyWaiting; Dllist* notifyList; char *pguser; /* Postgres username of user who is connected */ + char *pgpass; + char *pgauth; PGlobjfuncs *lobjfuncs; /* Backend function OID's for large object access */ } PGconn; -- 2.40.0