<commit_before>/* -*-pgsql-c-*- */
/*
 *
 * $Header$
 *
 * pgpool: a language independent connection pool server for PostgreSQL
 * written by <NAME>
 *
 * Portions Copyright (c) 2003-2010	PgPool Global Development Group
 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California                                          *
 * 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.
 *
 * pool_hba.c.: Routines to handle host based authentication.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <netdb.h>

#include "pool.h"
#include "pool_path.h"
#include "pool_ip.h"
#include "pool_stream.h"
#include "pool_config.h"
#include "parser/pool_memory.h"
#include "parser/pg_list.h"
#include "pool_passwd.h"

#define MULTI_VALUE_SEP "\001" /* delimiter for multi-valued column strings */
#define MAX_TOKEN	256

static List *hba_lines = NIL;
static List *hba_line_nums = NIL;
static char *hbaFileName;

static POOL_MEMORY_POOL *hba_memory_context = NULL;

static void sendAuthRequest(POOL_CONNECTION *frontend, AuthRequest areq);
static void auth_failed(POOL_CONNECTION *frontend);
static void close_all_backend_connections(void);
static bool hba_getauthmethod(POOL_CONNECTION *frontend);
static bool check_hba(POOL_CONNECTION *frontend);
static void parse_hba(List *line, int line_num, POOL_CONNECTION *frontend, bool *found_p, bool *error_p);
static void parse_hba_auth(ListCell **line_item, UserAuth *userauth_p, char **auth_arg_p, bool *error_p);
static bool check_user(char *user, char *param_str);
static bool check_db(char *dbname, char *user, char *param_str);
static void free_lines(List **lines, List **line_nums);
static void tokenize_file(const char *filename, FILE *file, List **lines, List **line_nums);
static char *tokenize_inc_file(const char *outer_filename, const char *inc_filename);
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(char *username);

#ifdef USE_PAM
#ifdef HAVE_PAM_PAM_APPL_H
#include <pam/pam_appl.h>
#endif
#ifdef HAVE_SECURITY_PAM_APPL_H
#include <security/pam_appl.h>
#endif

#define PGPOOL_PAM_SERVICE "pgpool" /* Service name passed to PAM */

static POOL_STATUS CheckPAMAuth(POOL_CONNECTION *frontend, char *user, char *password);
static int pam_passwd_conv_proc(int num_msg, const struct pam_message ** msg, struct pam_response ** resp, void *appdata_ptr);
/*
 * recv_password_packet is usually used with authentications that require a client
 * password. However, pgpool's hba function only uses it for PAM authentication,
 * so declare a prototype here in "#ifdef USE_PAM" to avoid compilation warning.
 */
static char *recv_password_packet(POOL_CONNECTION *frontend);

static struct pam_conv pam_passw_conv = {
	&pam_passwd_conv_proc,
	NULL
};

static char *pam_passwd = NULL;	/* Workaround for Solaris 2.6 brokenness */
static POOL_CONNECTION *pam_frontend_kludge; /* Workaround for passing
											  * POOL_CONNECTION *frontend
											  * into pam_passwd_conv_proc */
#endif /* USE_PAM */


/*
 * read in hba config file
 */
void load_hba(char *hbapath)
{
	FILE *file;

	POOL_MEMORY_POOL *old_context;
	if (hba_memory_context == NULL)
	{
		hba_memory_context = pool_memory_create(PARSER_BLOCK_SIZE);
		if (hba_memory_context == NULL)
		{
			pool_error("load_hba: pool_memory_create() failed");
			exit(1);
		}
	}
	/* switch memory context */
	old_context = pool_memory;
	pool_memory = hba_memory_context;

	if (hba_lines || hba_line_nums)
		free_lines(&hba_lines, &hba_line_nums);

	file = fopen(hbapath, "r");
	if (!file)
	{
		pool_error("could not open \"%s\". reason: %s",
				   hbapath, strerror(errno));
		exit(1);
	}

	pool_debug("loading \"%s\" for client authentication configuration file",
			   hbapath);

	tokenize_file(hbapath, file, &hba_lines, &hba_line_nums);
	fclose(file);

	hbaFileName = pstrdup(hbapath);

	/* switch old memory context */
	pool_memory = old_context;
}


/*
 * do frontend <-> pgpool authentication based on pool_hba.conf
 */
void ClientAuthentication(POOL_CONNECTION *frontend)
{
	POOL_STATUS status = POOL_ERROR;

	if (! hba_getauthmethod(frontend))
	{
		pool_error("missing or erroneous pool_hba.conf file");
		pool_send_error_message(frontend, frontend->protoVersion, "XX000",
								"missing or erroneous pool_hba.conf file", "",
								"See pgpool log for details.", __FILE__, __LINE__);
		close_all_backend_connections();
		/*<commit_msg>Fix load_hba() not to exit(1) if error occurs. If exit(1) is issued, pgpool main exits but children remain, which is not good.<commit_after>/* -*-pgsql-c-*- */
/*
 *
 * $Header$
 *
 * pgpool: a language independent connection pool server for PostgreSQL
 * written by <NAME>
 *
 * Portions Copyright (c) 2003-2010	PgPool Global Development Group
 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California                                          *
 * 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.
 *
 * pool_hba.c.: Routines to handle host based authentication.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <netdb.h>

#include "pool.h"
#include "pool_path.h"
#include "pool_ip.h"
#include "pool_stream.h"
#include "pool_config.h"
#include "parser/pool_memory.h"
#include "parser/pg_list.h"
#include "pool_passwd.h"

#define MULTI_VALUE_SEP "\001" /* delimiter for multi-valued column strings */
#define MAX_TOKEN	256

static List *hba_lines = NIL;
static List *hba_line_nums = NIL;
static char *hbaFileName;

static POOL_MEMORY_POOL *hba_memory_context = NULL;

static void sendAuthRequest(POOL_CONNECTION *frontend, AuthRequest areq);
static void auth_failed(POOL_CONNECTION *frontend);
static void close_all_backend_connections(void);
static bool hba_getauthmethod(POOL_CONNECTION *frontend);
static bool check_hba(POOL_CONNECTION *frontend);
static void parse_hba(List *line, int line_num, POOL_CONNECTION *frontend, bool *found_p, bool *error_p);
static void parse_hba_auth(ListCell **line_item, UserAuth *userauth_p, char **auth_arg_p, bool *error_p);
static bool check_user(char *user, char *param_str);
static bool check_db(char *dbname, char *user, char *param_str);
static void free_lines(List **lines, List **line_nums);
static void tokenize_file(const char *filename, FILE *file, List **lines, List **line_nums);
static char *tokenize_inc_file(const char *outer_filename, const char *inc_filename);
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(char *username);

#ifdef USE_PAM
#ifdef HAVE_PAM_PAM_APPL_H
#include <pam/pam_appl.h>
#endif
#ifdef HAVE_SECURITY_PAM_APPL_H
#include <security/pam_appl.h>
#endif

#define PGPOOL_PAM_SERVICE "pgpool" /* Service name passed to PAM */

static POOL_STATUS CheckPAMAuth(POOL_CONNECTION *frontend, char *user, char *password);
static int pam_passwd_conv_proc(int num_msg, const struct pam_message ** msg, struct pam_response ** resp, void *appdata_ptr);
/*
 * recv_password_packet is usually used with authentications that require a client
 * password. However, pgpool's hba function only uses it for PAM authentication,
 * so declare a prototype here in "#ifdef USE_PAM" to avoid compilation warning.
 */
static char *recv_password_packet(POOL_CONNECTION *frontend);

static struct pam_conv pam_passw_conv = {
	&pam_passwd_conv_proc,
	NULL
};

static char *pam_passwd = NULL;	/* Workaround for Solaris 2.6 brokenness */
static POOL_CONNECTION *pam_frontend_kludge; /* Workaround for passing
											  * POOL_CONNECTION *frontend
											  * into pam_passwd_conv_proc */
#endif /* USE_PAM */


/*
 * read in hba config file
 */
int load_hba(char *hbapath)
{
	FILE *file;

	POOL_MEMORY_POOL *old_context;
	if (hba_memory_context == NULL)
	{
		hba_memory_context = pool_memory_create(PARSER_BLOCK_SIZE);
		if (hba_memory_context == NULL)
		{
			pool_error("load_hba: pool_memory_create() failed");
			return -1;
		}
	}
	/* switch memory context */
	old_context = pool_memory;
	pool_memory = hba_memory_context;

	if (hba_lines || hba_line_nums)
		free_lines(&hba_lines, &hba_line_nums);

	file = fopen(hbapath, "r");
	if (!file)
	{
		pool_error("could not open \"%s\". reason: %s",
				   hbapath, strerror(errno));
		pool_memory_delete(hba_memory_context, 0);

		/* switch to old memory context */
		pool_memory = old_context;

		return -1;
	}

	pool_debug("loading \"%s\" for client authentication configuration file",
			   hbapath);

	tokenize_file(hbapath, file, &hba_lines, &hba_line_nums);
	fclose(file);

	hbaFileName = pstrdup(hbapath);

	/* switch to old memory context */
	pool_memory = old_context;

	return 0;
}


/*
 * do frontend <-> pgpool authentication based on pool_hba.conf
 */
void ClientAuthentication(POOL_CONNECTION *frontend)
{
	POOL_STATUS status = POOL_ERROR;

	if (! hba_getauthmethod(frontend))
	{
		pool_error("missing or erroneous pool_hba.conf file");
		pool_send_error_message(frontend, frontend->protoVersion, "XX000",
								"missing or erroneous pool_hba.conf file", "",
								"See pgpool log for details.", __FILE__, __LINE__);
		close_all_backend_connections();
		/*
{'fraction_non_alphanumeric': 0.09913387309357936, 'fraction_numerical': 0.0067783844850310675, 'mean_word_length': 4.891846921797005, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3245104', 'n_tokens_mistral': 3637, 'n_tokens_neox': 3453, 'n_words': 1059}