diff options
Diffstat (limited to 'src/backend/libpq/hba.c')
-rw-r--r-- | src/backend/libpq/hba.c | 1336 |
1 files changed, 770 insertions, 566 deletions
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c index 0cc2bbf6ac9..014eca14fa3 100644 --- a/src/backend/libpq/hba.c +++ b/src/backend/libpq/hba.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * hba.c-- - * Routines to handle host based authentication (that's the scheme - * wherein you authenticate a user by seeing what IP address the system - * says he comes from and possibly using ident). + * Routines to handle host based authentication (that's the scheme + * wherein you authenticate a user by seeing what IP address the system + * says he comes from and possibly using ident). * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.19 1997/08/27 03:48:31 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.20 1997/09/07 04:42:21 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -27,263 +27,356 @@ #include <libpq/libpq.h> #include <libpq/pqcomm.h> #include <libpq/hba.h> -#include <port/inet_aton.h> /* For inet_aton() */ +#include <port/inet_aton.h> /* For inet_aton() */ #include <storage/fd.h> /* Some standard C libraries, including GNU, have an isblank() function. Others, including Solaris, do not. So we have our own. */ -static bool -isblank(const char c) { - return(c == ' ' || c == 9 /* tab */); +static bool +isblank(const char c) +{ + return (c == ' ' || c == 9 /* tab */ ); } -static void -next_token(FILE *fp, char *buf, const int bufsz) { +static void +next_token(FILE * fp, char *buf, const int bufsz) +{ /*-------------------------------------------------------------------------- Grab one token out of fp. Tokens are strings of non-blank characters bounded by blank characters, beginning of line, and end - of line. Blank means space or tab. Return the token as *buf. + of line. Blank means space or tab. Return the token as *buf. Leave file positioned to character immediately after the token or EOF, whichever comes first. If no more tokens on line, return null string as *buf and position file to beginning of next line or EOF, - whichever comes first. + whichever comes first. --------------------------------------------------------------------------*/ - int c; - char *eb = buf+(bufsz-1); - - /* Move over inital token-delimiting blanks */ - while (isblank(c = getc(fp))) ; - - if (c != '\n') { - /* build a token in buf of next characters up to EOF, eol, or blank. */ - while (c != EOF && c != '\n' && !isblank(c)) { - if (buf < eb) *buf++ = c; - c = getc(fp); - /* Put back the char right after the token (putting back EOF is ok) */ - } - ungetc(c, fp); - } - *buf = '\0'; + int c; + char *eb = buf + (bufsz - 1); + + /* Move over inital token-delimiting blanks */ + while (isblank(c = getc(fp))); + + if (c != '\n') + { + + /* + * build a token in buf of next characters up to EOF, eol, or + * blank. + */ + while (c != EOF && c != '\n' && !isblank(c)) + { + if (buf < eb) + *buf++ = c; + c = getc(fp); + + /* + * Put back the char right after the token (putting back EOF + * is ok) + */ + } + ungetc(c, fp); + } + *buf = '\0'; } static void -read_through_eol(FILE *file) { - int c; - do - c = getc(file); - while (c != '\n' && c != EOF); +read_through_eol(FILE * file) +{ + int c; + + do + c = getc(file); + while (c != '\n' && c != EOF); } static void -read_hba_entry2(FILE *file, enum Userauth *userauth_p, char usermap_name[], - bool *error_p, bool *matches_p, bool find_password_entries) { +read_hba_entry2(FILE * file, enum Userauth * userauth_p, char usermap_name[], + 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 *error_p. ---------------------------------------------------------------------------*/ - char buf[MAX_TOKEN]; - - bool userauth_valid; - - /* Get authentication type token. */ - next_token(file, buf, sizeof(buf)); - userauth_valid = false; - if (buf[0] == '\0') { - *error_p = true; - } else { - userauth_valid = true; - if(strcmp(buf, "trust") == 0) { - *userauth_p = Trust; - } else if(strcmp(buf, "ident") == 0) { - *userauth_p = Ident; - } 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); - } 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 { - 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; - } - } + char buf[MAX_TOKEN]; + + bool userauth_valid; + + /* Get authentication type token. */ + next_token(file, buf, sizeof(buf)); + userauth_valid = false; + if (buf[0] == '\0') + { + *error_p = true; + } + else + { + userauth_valid = true; + if (strcmp(buf, "trust") == 0) + { + *userauth_p = Trust; + } + else if (strcmp(buf, "ident") == 0) + { + *userauth_p = Ident; + } + 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); + } + 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 + { + 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; + } + } } 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[], - bool find_password_entries) { +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[], + 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" to a database named "database[]". If so, return *matches_p true and *userauth_p and usermap_name[] as the values from the entry. If not, return matches_p false. If the record has a syntax error, - return *error_p true, after issuing a message to stderr. If no error, + return *error_p true, after issuing a message to stderr. If no error, leave *error_p as it was. ---------------------------------------------------------------------------*/ - char buf[MAX_TOKEN]; /* A token from the record */ - - /* Read the record type field */ - next_token(file, buf, sizeof(buf)); - if (buf[0] == '\0') *matches_p = false; - else { - /* if this isn't a "host" record, it can't match. */ - if (strcmp(buf, "host") != 0) { - *matches_p = false; - read_through_eol(file); - } else { - /* It's a "host" record. Read the database name field. */ - next_token(file, buf, sizeof(buf)); - if (buf[0] == '\0') *matches_p = false; - else { - /* If this record isn't for our database, ignore it. */ - if (strcmp(buf, database) != 0 && strcmp(buf, "all") != 0) { - *matches_p = false; - read_through_eol(file); - } else { - /* Read the IP address field */ - next_token(file, buf, sizeof(buf)); - if (buf[0] == '\0') *matches_p = false; - else { - int valid; /* Field is valid dotted decimal */ - /* Remember the IP address field and go get mask field */ - struct in_addr file_ip_addr; /* IP address field value */ - - valid = inet_aton(buf, &file_ip_addr); - if (!valid) { - *matches_p = false; - read_through_eol(file); - } else { - /* Read the mask field */ - next_token(file, buf, sizeof(buf)); - if (buf[0] == '\0') *matches_p = false; - else { - struct in_addr mask; - /* Got mask. Now see if this record is for our host. */ - valid = inet_aton(buf, &mask); - if (!valid) { - *matches_p = false; - read_through_eol(file); - } else { - if (((file_ip_addr.s_addr ^ ip_addr.s_addr) & mask.s_addr) - != 0x0000) { - *matches_p = false; - read_through_eol(file); - } else { - /* This is the record we're looking for. Read - the rest of the info from it. - */ - read_hba_entry2(file, userauth_p, usermap_name, - error_p, matches_p, find_password_entries); - if (*error_p) { - sprintf(PQerrormsg, - "process_hba_record: invalid syntax in " - "hba config file " - "for host record for IP address %s\n", - inet_ntoa(file_ip_addr)); - fputs(PQerrormsg, stderr); - pqdebug("%s", PQerrormsg); - } - } - } - } - } - } - } - } - } - } + char buf[MAX_TOKEN]; /* A token from the record */ + + /* Read the record type field */ + next_token(file, buf, sizeof(buf)); + if (buf[0] == '\0') + *matches_p = false; + else + { + /* if this isn't a "host" record, it can't match. */ + if (strcmp(buf, "host") != 0) + { + *matches_p = false; + read_through_eol(file); + } + else + { + /* It's a "host" record. Read the database name field. */ + next_token(file, buf, sizeof(buf)); + if (buf[0] == '\0') + *matches_p = false; + else + { + /* If this record isn't for our database, ignore it. */ + if (strcmp(buf, database) != 0 && strcmp(buf, "all") != 0) + { + *matches_p = false; + read_through_eol(file); + } + else + { + /* Read the IP address field */ + next_token(file, buf, sizeof(buf)); + if (buf[0] == '\0') + *matches_p = false; + else + { + int valid; /* Field is valid dotted + * decimal */ + + /* + * Remember the IP address field and go get mask + * field + */ + struct in_addr file_ip_addr; /* IP address field + * value */ + + valid = inet_aton(buf, &file_ip_addr); + if (!valid) + { + *matches_p = false; + read_through_eol(file); + } + else + { + /* Read the mask field */ + next_token(file, buf, sizeof(buf)); + if (buf[0] == '\0') + *matches_p = false; + else + { + struct in_addr mask; + + /* + * Got mask. Now see if this record is + * for our host. + */ + valid = inet_aton(buf, &mask); + if (!valid) + { + *matches_p = false; + read_through_eol(file); + } + else + { + if (((file_ip_addr.s_addr ^ ip_addr.s_addr) & mask.s_addr) + != 0x0000) + { + *matches_p = false; + read_through_eol(file); + } + else + { + + /* + * This is the record we're + * looking for. Read the rest of + * the info from it. + */ + read_hba_entry2(file, userauth_p, usermap_name, + error_p, matches_p, find_password_entries); + if (*error_p) + { + sprintf(PQerrormsg, + "process_hba_record: invalid syntax in " + "hba config file " + "for host record for IP address %s\n", + inet_ntoa(file_ip_addr)); + fputs(PQerrormsg, stderr); + pqdebug("%s", PQerrormsg); + } + } + } + } + } + } + } + } + } + } } 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[], bool find_password_entries) { +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[], 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". ----------------------------------------------------------------------------*/ - bool found_entry; - /* We've processed a record that applies to our connection */ - bool error; - /* Said record has invalid syntax. */ - bool eof; /* We've reached the end of the file we're reading */ - - found_entry = false; /* initial value */ - error = false; /* initial value */ - eof = false; /* initial value */ - while (!eof && !found_entry && !error) { - /* Process a line from the config file */ - - int c; /* a character read from the file */ - - c = getc(file); ungetc(c, file); - if (c == EOF) eof = true; - else { - if (c == '#') read_through_eol(file); - else { - process_hba_record(file, ip_addr, database, - &found_entry, &error, userauth_p, usermap_name, - find_password_entries); - } - } - } - if (found_entry) { - if (error) *host_ok_p = false; - else *host_ok_p = true; - } else *host_ok_p = false; -} + bool found_entry; + + /* We've processed a record that applies to our connection */ + bool error; + + /* Said record has invalid syntax. */ + bool eof; /* We've reached the end of the file we're + * reading */ + + found_entry = false; /* initial value */ + error = false; /* initial value */ + eof = false; /* initial value */ + while (!eof && !found_entry && !error) + { + /* Process a line from the config file */ + + int c; /* a character read from the file */ + + c = getc(file); + ungetc(c, file); + if (c == EOF) + eof = true; + else + { + if (c == '#') + read_through_eol(file); + else + { + process_hba_record(file, ip_addr, database, + &found_entry, &error, userauth_p, usermap_name, + find_password_entries); + } + } + } + if (found_entry) + { + if (error) + *host_ok_p = false; + else + *host_ok_p = true; + } + else + *host_ok_p = false; +} 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) { +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) +{ /*-------------------------------------------------------------------------- Read the config file and find an entry that allows connection from - host "ip_addr" to database "database". If not found, return - *host_ok_p == false. If found, return *userauth_p and *usermap_name + host "ip_addr" to database "database". If not found, return + *host_ok_p == false. If found, return *userauth_p and *usermap_name representing the contents of that entry. When a record has invalid syntax, we either ignore it or reject the @@ -298,133 +391,167 @@ find_hba_entry(const char DataDir[], const struct in_addr ip_addr, follow directions and just installed his old hba file in the new database system. ----------------------------------------------------------------------------*/ - int fd; - - FILE *file; /* The config file we have to read */ - - char *old_conf_file; - /* The name of old config file that better not exist. */ - - /* Fail if config file by old name exists. */ - - - /* put together the full pathname to the old config file */ - old_conf_file = (char *) malloc((strlen(DataDir) + - strlen(OLD_CONF_FILE)+2)*sizeof(char)); - sprintf(old_conf_file, "%s/%s", DataDir, OLD_CONF_FILE); - - if ((fd = open(old_conf_file,O_RDONLY,0)) != -1) { - /* Old config file exists. Tell this guy he needs to upgrade. */ - close(fd); - sprintf(PQerrormsg, - "A file exists by the name used for host-based authentication " - "in prior releases of Postgres (%s). The name and format of " - "the configuration file have changed, so this file should be " - "converted.\n", - old_conf_file); - fputs(PQerrormsg, stderr); - pqdebug("%s", PQerrormsg); - } else { - char *conf_file; /* The name of the config file we have to read */ - - /* put together the full pathname to the config file */ - conf_file = (char *) malloc((strlen(DataDir) + - strlen(CONF_FILE)+2)*sizeof(char)); - sprintf(conf_file, "%s/%s", DataDir, CONF_FILE); - - file = AllocateFile(conf_file, "r"); - if (file == NULL) { - /* The open of the config file failed. */ - - *host_ok_p = false; - - sprintf(PQerrormsg, - "find_hba_entry: Host-based authentication config file " - "does not exist or permissions are not setup correctly! " - "Unable to open file \"%s\".\n", - conf_file); - fputs(PQerrormsg, stderr); - pqdebug("%s", PQerrormsg); - } else { - process_open_config_file(file, ip_addr, database, host_ok_p, userauth_p, - usermap_name, find_password_entries); - FreeFile(file); - } - free(conf_file); - } - free(old_conf_file); - return; +---------------------------------------------------------------------------*/ + int fd; + + FILE *file; /* The config file we have to read */ + + char *old_conf_file; + + /* The name of old config file that better not exist. */ + + /* Fail if config file by old name exists. */ + + + /* put together the full pathname to the old config file */ + old_conf_file = (char *) malloc((strlen(DataDir) + + strlen(OLD_CONF_FILE) + 2) * sizeof(char)); + sprintf(old_conf_file, "%s/%s", DataDir, OLD_CONF_FILE); + + if ((fd = open(old_conf_file, O_RDONLY, 0)) != -1) + { + /* Old config file exists. Tell this guy he needs to upgrade. */ + close(fd); + sprintf(PQerrormsg, + "A file exists by the name used for host-based authentication " + "in prior releases of Postgres (%s). The name and format of " + "the configuration file have changed, so this file should be " + "converted.\n", + old_conf_file); + fputs(PQerrormsg, stderr); + pqdebug("%s", PQerrormsg); + } + else + { + char *conf_file; /* The name of the config file we + * have to read */ + + /* put together the full pathname to the config file */ + conf_file = (char *) malloc((strlen(DataDir) + + strlen(CONF_FILE) + 2) * sizeof(char)); + sprintf(conf_file, "%s/%s", DataDir, CONF_FILE); + + file = AllocateFile(conf_file, "r"); + if (file == NULL) + { + /* The open of the config file failed. */ + + *host_ok_p = false; + + sprintf(PQerrormsg, + "find_hba_entry: Host-based authentication config file " + "does not exist or permissions are not setup correctly! " + "Unable to open file \"%s\".\n", + conf_file); + fputs(PQerrormsg, stderr); + pqdebug("%s", PQerrormsg); + } + else + { + process_open_config_file(file, ip_addr, database, host_ok_p, userauth_p, + usermap_name, find_password_entries); + FreeFile(file); + } + free(conf_file); + } + free(old_conf_file); + return; } static void -interpret_ident_response(char ident_response[], - bool *error_p, char ident_username[]) { +interpret_ident_response(char ident_response[], + bool * error_p, char ident_username[]) +{ /*---------------------------------------------------------------------------- Parse the string "ident_response[]" as a response from a query to an Ident - server. If it's a normal response indicating a username, return + server. If it's a normal response indicating a username, return *error_p == false and the username as ident_username[]. If it's anything else, return *error_p == true and ident_username[] undefined. ----------------------------------------------------------------------------*/ - char *cursor; /* Cursor into ident_response[] */ - - cursor = &ident_response[0]; - - /* Ident's response, in the telnet tradition, should end in crlf (\r\n). */ - if (strlen(ident_response) < 2) *error_p = true; - else if (ident_response[strlen(ident_response)-2] != '\r') *error_p = true; - else { - while (*cursor != ':' && *cursor != '\r') cursor++; /* skip port field */ - - if (*cursor != ':') *error_p = true; - else { - /* We're positioned to colon before response type field */ - char response_type[80]; - int i; /* Index into response_type[] */ - cursor++; /* Go over colon */ - while (isblank(*cursor)) cursor++; /* skip blanks */ - i = 0; - while (*cursor != ':' && *cursor != '\r' && !isblank(*cursor) - && i < sizeof(response_type)-1) - response_type[i++] = *cursor++; - response_type[i] = '\0'; - while (isblank(*cursor)) cursor++; /* skip blanks */ - if (strcmp(response_type, "USERID") != 0) - *error_p = true; - else { - /* It's a USERID response. Good. "cursor" should be pointing to - the colon that precedes the operating system type. - */ - if (*cursor != ':') *error_p = true; - else { - cursor++; /* Go over colon */ - /* Skip over operating system field. */ - while (*cursor != ':' && *cursor != '\r') cursor++; - if (*cursor != ':') *error_p = true; - else { - int i; /* Index into ident_username[] */ - cursor ++; /* Go over colon */ - while (isblank(*cursor)) cursor++; /* skip blanks */ - /* Rest of line is username. Copy it over. */ - i = 0; - while (*cursor != '\r' && i < IDENT_USERNAME_MAX) - ident_username[i++] = *cursor++; - ident_username[i] = '\0'; - *error_p = false; - } - } - } - } - } + char *cursor; /* Cursor into ident_response[] */ + + cursor = &ident_response[0]; + + /* + * Ident's response, in the telnet tradition, should end in crlf + * (\r\n). + */ + if (strlen(ident_response) < 2) + *error_p = true; + else if (ident_response[strlen(ident_response) - 2] != '\r') + *error_p = true; + else + { + while (*cursor != ':' && *cursor != '\r') + cursor++; /* skip port field */ + + if (*cursor != ':') + *error_p = true; + else + { + /* We're positioned to colon before response type field */ + char response_type[80]; + int i; /* Index into response_type[] */ + + cursor++; /* Go over colon */ + while (isblank(*cursor)) + cursor++; /* skip blanks */ + i = 0; + while (*cursor != ':' && *cursor != '\r' && !isblank(*cursor) + && i < sizeof(response_type) - 1) + response_type[i++] = *cursor++; + response_type[i] = '\0'; + while (isblank(*cursor)) + cursor++; /* skip blanks */ + if (strcmp(response_type, "USERID") != 0) + *error_p = true; + else + { + + /* + * It's a USERID response. Good. "cursor" should be + * pointing to the colon that precedes the operating + * system type. + */ + if (*cursor != ':') + *error_p = true; + else + { + cursor++; /* Go over colon */ + /* Skip over operating system field. */ + while (*cursor != ':' && *cursor != '\r') + cursor++; + if (*cursor != ':') + *error_p = true; + else + { + int i; /* Index into + * ident_username[] */ + + cursor++; /* Go over colon */ + while (isblank(*cursor)) + cursor++; /* skip blanks */ + /* Rest of line is username. Copy it over. */ + i = 0; + while (*cursor != '\r' && i < IDENT_USERNAME_MAX) + ident_username[i++] = *cursor++; + ident_username[i] = '\0'; + *error_p = false; + } + } + } + } + } } static void ident(const struct in_addr remote_ip_addr, const struct in_addr local_ip_addr, - const ushort remote_port, const ushort local_port, - bool *ident_failed, char ident_username[]) { + const ushort remote_port, const ushort local_port, + bool * ident_failed, char ident_username[]) +{ /*-------------------------------------------------------------------------- Talk to the ident server on host "remote_ip_addr" and find out who owns the tcp connection from his port "remote_port" to port @@ -437,169 +564,204 @@ ident(const struct in_addr remote_ip_addr, const struct in_addr local_ip_addr, *ident_failed == true (and ident_username[] undefined). ----------------------------------------------------------------------------*/ - int sock_fd; - /* File descriptor for socket on which we talk to Ident */ - - int rc; /* Return code from a locally called function */ - - sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); - if (sock_fd == -1) { - sprintf(PQerrormsg, - "Failed to create socket on which to talk to Ident server. " - "socket() returned errno = %s (%d)\n", - strerror(errno), errno); - fputs(PQerrormsg, stderr); - pqdebug("%s", PQerrormsg); - } else { - struct sockaddr_in ident_server; - /* Socket address of Ident server on the system from which client - is attempting to connect to us. - */ - ident_server.sin_family = AF_INET; - ident_server.sin_port = htons(IDENT_PORT); - ident_server.sin_addr = remote_ip_addr; - rc = connect(sock_fd, - (struct sockaddr *) &ident_server, sizeof(ident_server)); - if (rc != 0) { - sprintf(PQerrormsg, - "Unable to connect to Ident server on the host which is " - "trying to connect to Postgres " - "(IP address %s, Port %d). " - "errno = %s (%d)\n", - inet_ntoa(remote_ip_addr), IDENT_PORT, strerror(errno), errno); - fputs(PQerrormsg, stderr); - pqdebug("%s", PQerrormsg); - *ident_failed = true; - } else { - char ident_query[80]; - /* The query we send to the Ident server */ - sprintf(ident_query, "%d,%d\n", - ntohs(remote_port), ntohs(local_port)); - rc = send(sock_fd, ident_query, strlen(ident_query), 0); - if (rc < 0) { - sprintf(PQerrormsg, - "Unable to send query to Ident server on the host which is " - "trying to connect to Postgres (Host %s, Port %d)," - "even though we successfully connected to it. " - "errno = %s (%d)\n", - inet_ntoa(remote_ip_addr), IDENT_PORT, strerror(errno), errno); - fputs(PQerrormsg, stderr); - pqdebug("%s", PQerrormsg); - *ident_failed = true; - } else { - char ident_response[80+IDENT_USERNAME_MAX]; - rc = recv(sock_fd, ident_response, sizeof(ident_response)-1, 0); - if (rc < 0) { - sprintf(PQerrormsg, - "Unable to receive response from Ident server " - "on the host which is " - "trying to connect to Postgres (Host %s, Port %d)," - "even though we successfully sent our query to it. " - "errno = %s (%d)\n", - inet_ntoa(remote_ip_addr), IDENT_PORT, - strerror(errno), errno); - fputs(PQerrormsg, stderr); - pqdebug("%s", PQerrormsg); - *ident_failed = true; - } else { - bool error; /* response from Ident is garbage. */ - ident_response[rc] = '\0'; - interpret_ident_response(ident_response, &error, ident_username); - *ident_failed = error; - } - } - close(sock_fd); - } - } + int sock_fd; + + /* File descriptor for socket on which we talk to Ident */ + + int rc; /* Return code from a locally called + * function */ + + sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + if (sock_fd == -1) + { + sprintf(PQerrormsg, + "Failed to create socket on which to talk to Ident server. " + "socket() returned errno = %s (%d)\n", + strerror(errno), errno); + fputs(PQerrormsg, stderr); + pqdebug("%s", PQerrormsg); + } + else + { + struct sockaddr_in ident_server; + + /* + * Socket address of Ident server on the system from which client + * is attempting to connect to us. + */ + ident_server.sin_family = AF_INET; + ident_server.sin_port = htons(IDENT_PORT); + ident_server.sin_addr = remote_ip_addr; + rc = connect(sock_fd, + (struct sockaddr *) & ident_server, sizeof(ident_server)); + if (rc != 0) + { + sprintf(PQerrormsg, + "Unable to connect to Ident server on the host which is " + "trying to connect to Postgres " + "(IP address %s, Port %d). " + "errno = %s (%d)\n", + inet_ntoa(remote_ip_addr), IDENT_PORT, strerror(errno), errno); + fputs(PQerrormsg, stderr); + pqdebug("%s", PQerrormsg); + *ident_failed = true; + } + else + { + char ident_query[80]; + + /* The query we send to the Ident server */ + sprintf(ident_query, "%d,%d\n", + ntohs(remote_port), ntohs(local_port)); + rc = send(sock_fd, ident_query, strlen(ident_query), 0); + if (rc < 0) + { + sprintf(PQerrormsg, + "Unable to send query to Ident server on the host which is " + "trying to connect to Postgres (Host %s, Port %d)," + "even though we successfully connected to it. " + "errno = %s (%d)\n", + inet_ntoa(remote_ip_addr), IDENT_PORT, strerror(errno), errno); + fputs(PQerrormsg, stderr); + pqdebug("%s", PQerrormsg); + *ident_failed = true; + } + else + { + char ident_response[80 + IDENT_USERNAME_MAX]; + + rc = recv(sock_fd, ident_response, sizeof(ident_response) - 1, 0); + if (rc < 0) + { + sprintf(PQerrormsg, + "Unable to receive response from Ident server " + "on the host which is " + "trying to connect to Postgres (Host %s, Port %d)," + "even though we successfully sent our query to it. " + "errno = %s (%d)\n", + inet_ntoa(remote_ip_addr), IDENT_PORT, + strerror(errno), errno); + fputs(PQerrormsg, stderr); + pqdebug("%s", PQerrormsg); + *ident_failed = true; + } + else + { + bool error; /* response from Ident is + * garbage. */ + + ident_response[rc] = '\0'; + interpret_ident_response(ident_response, &error, ident_username); + *ident_failed = error; + } + } + close(sock_fd); + } + } } static void -parse_map_record(FILE *file, - char file_map[], char file_pguser[], char file_iuser[]) { +parse_map_record(FILE * file, + char file_map[], char file_pguser[], char file_iuser[]) +{ /*--------------------------------------------------------------------------- Take the noncomment line which is next on file "file" and interpret it as a line in a usermap file. Specifically, return the first - 3 tokens as file_map, file_iuser, and file_pguser, respectively. If + 3 tokens as file_map, file_iuser, and file_pguser, respectively. If there are fewer than 3 tokens, return null strings for the missing ones. ---------------------------------------------------------------------------*/ - char buf[MAX_TOKEN]; - /* A token read from the file */ - - /* Set defaults in case fields not in file */ - file_map[0] = '\0'; - file_pguser[0] = '\0'; - file_iuser[0] = '\0'; - - next_token(file, buf, sizeof(buf)); - if (buf != '\0') { - strcpy(file_map, buf); - next_token(file, buf, sizeof(buf)); - if (buf != '\0') { - strcpy(file_iuser, buf); - next_token(file, buf, sizeof(buf)); - if (buf != '\0') { - strcpy(file_pguser, buf); - read_through_eol(file); - } - } - } + char buf[MAX_TOKEN]; + + /* A token read from the file */ + + /* Set defaults in case fields not in file */ + file_map[0] = '\0'; + file_pguser[0] = '\0'; + file_iuser[0] = '\0'; + + next_token(file, buf, sizeof(buf)); + if (buf != '\0') + { + strcpy(file_map, buf); + next_token(file, buf, sizeof(buf)); + if (buf != '\0') + { + strcpy(file_iuser, buf); + next_token(file, buf, sizeof(buf)); + if (buf != '\0') + { + strcpy(file_pguser, buf); + read_through_eol(file); + } + } + } } static void -verify_against_open_usermap(FILE *file, - const char pguser[], - const char ident_username[], - const char usermap_name[], - bool *checks_out_p) { +verify_against_open_usermap(FILE * file, + const char pguser[], + const char ident_username[], + const char usermap_name[], + bool * checks_out_p) +{ /*-------------------------------------------------------------------------- This function does the same thing as verify_against_usermap, only with the config file already open on stream descriptor "file". ---------------------------------------------------------------------------*/ - bool match; /* We found a matching entry in the map file */ - bool eof; /* We've reached the end of the file we're reading */ - - match = false; /* initial value */ - eof = false; /* initial value */ - while (!eof && !match) { - /* Process a line from the map file */ - - int c; /* a character read from the file */ - - c = getc(file); ungetc(c, file); - if (c == EOF) eof = true; - else { - if (c == '#') read_through_eol(file); - else { - /* The following are fields read from a record of the file */ - char file_map[MAX_TOKEN+1]; - char file_pguser[MAX_TOKEN+1]; - char file_iuser[MAX_TOKEN+1]; - - parse_map_record(file, file_map, file_pguser, file_iuser); - if (strcmp(file_map, usermap_name) == 0 && - strcmp(file_pguser, pguser) == 0 && - strcmp(file_iuser, ident_username) == 0) - match = true; - } - } - } - *checks_out_p = match; + bool match; /* We found a matching entry in the map + * file */ + bool eof; /* We've reached the end of the file we're + * reading */ + + match = false; /* initial value */ + eof = false; /* initial value */ + while (!eof && !match) + { + /* Process a line from the map file */ + + int c; /* a character read from the file */ + + c = getc(file); + ungetc(c, file); + if (c == EOF) + eof = true; + else + { + if (c == '#') + read_through_eol(file); + else + { + /* The following are fields read from a record of the file */ + char file_map[MAX_TOKEN + 1]; + char file_pguser[MAX_TOKEN + 1]; + char file_iuser[MAX_TOKEN + 1]; + + parse_map_record(file, file_map, file_pguser, file_iuser); + if (strcmp(file_map, usermap_name) == 0 && + strcmp(file_pguser, pguser) == 0 && + strcmp(file_iuser, ident_username) == 0) + match = true; + } + } + } + *checks_out_p = match; } static void verify_against_usermap(const char DataDir[], - const char pguser[], - const char ident_username[], - const char usermap_name[], - bool *checks_out_p) { + const char pguser[], + const char ident_username[], + const char usermap_name[], + bool * checks_out_p) +{ /*-------------------------------------------------------------------------- See if the user with ident username "ident_username" is allowed to act as Postgres user "pguser" according to usermap "usermap_name". Look @@ -610,151 +772,194 @@ verify_against_usermap(const char DataDir[], "ident_username" in order to be authorized. Iff authorized, return *checks_out_p == true. - + --------------------------------------------------------------------------*/ - if (usermap_name[0] == '\0') { - *checks_out_p = false; - sprintf(PQerrormsg, - "verify_against_usermap: hba configuration file does not " - "have the usermap field filled in in the entry that pertains " - "to this connection. That field is essential for Ident-based " - "authentication.\n"); - fputs(PQerrormsg, stderr); - pqdebug("%s", PQerrormsg); - } else if (strcmp(usermap_name, "sameuser") == 0) { - if (strcmp(ident_username, pguser) == 0) *checks_out_p = true; - else *checks_out_p = false; - } else { - FILE *file; /* The map file we have to read */ - - char *map_file; /* The name of the map file we have to read */ - - /* put together the full pathname to the map file */ - map_file = (char *) malloc((strlen(DataDir) + - strlen(MAP_FILE)+2)*sizeof(char)); - sprintf(map_file, "%s/%s", DataDir, MAP_FILE); - - file = AllocateFile(map_file, "r"); - if (file == NULL) { - /* The open of the map file failed. */ - - *checks_out_p = false; - - sprintf(PQerrormsg, - "verify_against_usermap: usermap file for Ident-based " - "authentication " - "does not exist or permissions are not setup correctly! " - "Unable to open file \"%s\".\n", - map_file); - fputs(PQerrormsg, stderr); - pqdebug("%s", PQerrormsg); - } else { - verify_against_open_usermap(file, - pguser, ident_username, usermap_name, - checks_out_p); - FreeFile(file); - } - free(map_file); - - - } + if (usermap_name[0] == '\0') + { + *checks_out_p = false; + sprintf(PQerrormsg, + "verify_against_usermap: hba configuration file does not " + "have the usermap field filled in in the entry that pertains " + "to this connection. That field is essential for Ident-based " + "authentication.\n"); + fputs(PQerrormsg, stderr); + pqdebug("%s", PQerrormsg); + } + else if (strcmp(usermap_name, "sameuser") == 0) + { + if (strcmp(ident_username, pguser) == 0) + *checks_out_p = true; + else + *checks_out_p = false; + } + else + { + FILE *file; /* The map file we have to read */ + + char *map_file; /* The name of the map file we + * have to read */ + + /* put together the full pathname to the map file */ + map_file = (char *) malloc((strlen(DataDir) + + strlen(MAP_FILE) + 2) * sizeof(char)); + sprintf(map_file, "%s/%s", DataDir, MAP_FILE); + + file = AllocateFile(map_file, "r"); + if (file == NULL) + { + /* The open of the map file failed. */ + + *checks_out_p = false; + + sprintf(PQerrormsg, + "verify_against_usermap: usermap file for Ident-based " + "authentication " + "does not exist or permissions are not setup correctly! " + "Unable to open file \"%s\".\n", + map_file); + fputs(PQerrormsg, stderr); + pqdebug("%s", PQerrormsg); + } + else + { + verify_against_open_usermap(file, + pguser, ident_username, usermap_name, + checks_out_p); + FreeFile(file); + } + free(map_file); + + + } } static void -authident(const char DataDir[], - const Port port, const char postgres_username[], - const char usermap_name[], - bool *authentic_p) { +authident(const char DataDir[], + const Port port, const char postgres_username[], + const char usermap_name[], + bool * authentic_p) +{ /*--------------------------------------------------------------------------- - Talk to the ident server on the remote host and find out who owns the + Talk to the ident server on the remote host and find out who owns the connection described by "port". Then look in the usermap file under - the usermap usermap_name[] and see if that user is equivalent to + the usermap usermap_name[] and see if that user is equivalent to Postgres user user[]. Return *authentic_p true iff yes. ---------------------------------------------------------------------------*/ - bool ident_failed; - /* We were unable to get ident to give us a username */ - char ident_username[IDENT_USERNAME_MAX+1]; - /* The username returned by ident */ - - ident(port.raddr.sin_addr, port.laddr.sin_addr, - port.raddr.sin_port, port.laddr.sin_port, - &ident_failed, ident_username); - - if (ident_failed) *authentic_p = false; - else { - bool checks_out; - verify_against_usermap(DataDir, - postgres_username, ident_username, usermap_name, - &checks_out); - if (checks_out) *authentic_p = true; - else *authentic_p = false; - } + bool ident_failed; + + /* We were unable to get ident to give us a username */ + char ident_username[IDENT_USERNAME_MAX + 1]; + + /* The username returned by ident */ + + ident(port.raddr.sin_addr, port.laddr.sin_addr, + port.raddr.sin_port, port.laddr.sin_port, + &ident_failed, ident_username); + + if (ident_failed) + *authentic_p = false; + else + { + bool checks_out; + + verify_against_usermap(DataDir, + postgres_username, ident_username, usermap_name, + &checks_out); + if (checks_out) + *authentic_p = true; + else + *authentic_p = false; + } } extern int -hba_recvauth(const Port *port, const char database[], const char user[], - const char DataDir[]) { +hba_recvauth(const Port * port, const char database[], const char user[], + const char DataDir[]) +{ /*--------------------------------------------------------------------------- Determine if the TCP connection described by "port" is with someone allowed to act as user "user" and access database "database". Return STATUS_OK if yes; STATUS_ERROR if not. -----------------------------------------------------------------------------*/ - bool host_ok; - /* There's an entry for this database and remote host in the pg_hba file */ - char usermap_name[USERMAP_NAME_SIZE+1]; - /* The name of the map pg_hba specifies for this connection (or special - value "SAMEUSER") - */ - enum Userauth userauth; - /* The type of user authentication pg_hba specifies for this connection */ - int retvalue; - /* Our eventual return value */ - - - find_hba_entry(DataDir, port->raddr.sin_addr, database, - &host_ok, &userauth, usermap_name, - false /* don't find password entries of type 'password' */); - - if (!host_ok) retvalue = STATUS_ERROR; - else { - switch (userauth) { - case Trust: - retvalue = STATUS_OK; - break; - case Ident: { - /* Here's where we need to call up ident and authenticate the user */ - - bool authentic; /* He is who he says he is. */ - - authident(DataDir, *port, user, usermap_name, &authentic); - - if (authentic) retvalue = STATUS_OK; - else retvalue = STATUS_ERROR; - } - break; - default: - retvalue = STATUS_ERROR; - Assert(false); - } - } - return(retvalue); +----------------------------------------------------------------------------*/ + bool host_ok; + + /* + * There's an entry for this database and remote host in the pg_hba + * file + */ + char usermap_name[USERMAP_NAME_SIZE + 1]; + + /* + * The name of the map pg_hba specifies for this connection (or + * special value "SAMEUSER") + */ + enum Userauth userauth; + + /* + * The type of user authentication pg_hba specifies for this + * connection + */ + int retvalue; + + /* Our eventual return value */ + + + find_hba_entry(DataDir, port->raddr.sin_addr, database, + &host_ok, &userauth, usermap_name, + false /* don't find password entries of type + 'password' */ ); + + if (!host_ok) + retvalue = STATUS_ERROR; + else + { + switch (userauth) + { + case Trust: + retvalue = STATUS_OK; + break; + case Ident: + { + + /* + * Here's where we need to call up ident and authenticate + * the user + */ + + bool authentic; /* He is who he says he + * is. */ + + authident(DataDir, *port, user, usermap_name, &authentic); + + if (authentic) + retvalue = STATUS_OK; + else + retvalue = STATUS_ERROR; + } + break; + default: + retvalue = STATUS_ERROR; + Assert(false); + } + } + return (retvalue); } /*---------------------------------------------------------------- * This version of hba was written by Bryan Henderson - * in September 1996 for Release 6.0. It changed the format of the + * in September 1996 for Release 6.0. It changed the format of the * hba file and added ident function. * * Here are some notes about the original host based authentication - * the preceded this one. + * the preceded this one. * * based on the securelib package originally written by William * LeFebvre, EECS Department, Northwestern University @@ -765,4 +970,3 @@ hba_recvauth(const Port *port, const char database[], const char user[], * (pnfisher@unity.ncsu.edu) * -----------------------------------------------------------------*/ - |