File broker_acl.c¶
File List > broker > broker_acl.c
Go to the documentation of this file
/*
* Copyright 2008 Search Solution Corporation
* Copyright 2016 CUBRID Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/*
* broker_acl.c -
*/
#ident "$Id$"
#include <assert.h>
#include <errno.h>
#include "porting.h"
#include "broker_acl.h"
#include "cas_error.h"
#include "broker_util.h"
#include "broker_filename.h"
#define ADMIN_ERR_MSG_SIZE BROKER_PATH_MAX * 2
#define ACCESS_FILE_DELIMITER ":"
#define IP_FILE_DELIMITER ","
#define NUM_ACL_ELEM 3
ACCESS_INFO access_info[ACL_MAX_ITEM_COUNT];
int num_access_info;
int access_info_changed;
typedef enum
{
ACL_FMT_NO_ERROR = 0,
ACL_FMT_UNKOWN_BROKER,
ACL_FMT_INVALID,
ACL_FMT_EMPTY_ELEM
} ACL_FMT;
static ACCESS_INFO *access_control_find_access_info (ACCESS_INFO ai[], int size, char *dbname, char *dbuser);
static int access_control_read_ip_info (IP_INFO * ip_info, char *filename, char *admin_err_msg);
static int access_control_check_right_internal (T_SHM_APPL_SERVER * shm_as_p, char *dbname, char *dbuser,
unsigned char *address);
static int access_control_check_ip (T_SHM_APPL_SERVER * shm_as_p, IP_INFO * ip_info, unsigned char *address,
int info_index);
static int record_ip_access_time (T_SHM_APPL_SERVER * shm_as_p, int info_index, int list_index);
static ACL_FMT is_invalid_acl_entry (const char *buf, T_SHM_BROKER * shm_br);
int
access_control_set_shm (T_SHM_APPL_SERVER * shm_as_p, T_BROKER_INFO * br_info_p, T_SHM_BROKER * shm_br,
char *admin_err_msg)
{
shm_as_p->access_control = shm_br->access_control;
shm_as_p->acl_default_policy = shm_br->acl_default_policy;
shm_as_p->acl_chn = 0;
if (shm_br->access_control && shm_br->access_control_file[0] != '\0')
{
char *access_file_name;
#if defined (WINDOWS)
char sem_name[BROKER_NAME_LEN];
MAKE_ACL_SEM_NAME (sem_name, br_info_p->name);
if (uw_sem_init (sem_name) < 0)
{
sprintf (admin_err_msg, "%s: cannot initialize acl semaphore", br_info_p->name);
return -1;
}
#else
if (uw_sem_init (&shm_as_p->acl_sem) < 0)
{
sprintf (admin_err_msg, "%s: cannot initialize acl semaphore", br_info_p->name);
return -1;
}
#endif
if (shm_br->access_control_file[0] != '\0')
{
set_cubrid_file (FID_ACCESS_CONTROL_FILE, shm_br->access_control_file);
access_file_name = get_cubrid_file_ptr (FID_ACCESS_CONTROL_FILE);
if (access_control_read_config_file (shm_as_p, access_file_name, admin_err_msg, shm_br) != 0)
{
return -1;
}
}
}
memcpy (shm_as_p->local_ip_addr, shm_br->my_ip_addr, 4);
return 0;
}
static ACCESS_INFO *
access_control_find_access_info (ACCESS_INFO ai[], int size, char *dbname, char *dbuser)
{
int i;
for (i = 0; i < size; i++)
{
if (strcmp (ai[i].dbname, dbname) == 0 && strcmp (ai[i].dbuser, dbuser) == 0)
{
return &ai[i];
}
}
return NULL;
}
int
access_control_read_config_file (T_SHM_APPL_SERVER * shm_appl, char *filename, char *admin_err_msg,
T_SHM_BROKER * shm_br)
{
char buf[1024], path_buf[BROKER_PATH_MAX], *files, *token, *save = NULL;
FILE *fd_access_list;
int num_access_list = 0, line = 0;
ACCESS_INFO new_access_info[ACL_MAX_ITEM_COUNT];
ACCESS_INFO *access_info;
bool is_current_broker_section = false;
ACL_FMT ret = ACL_FMT_NO_ERROR;
size_t filename_len;
#if defined(WINDOWS)
char acl_sem_name[BROKER_NAME_LEN];
#endif
fd_access_list = fopen (filename, "r");
if (fd_access_list == NULL)
{
sprintf (admin_err_msg, "%s: error while loading access control file(%s)", shm_appl->broker_name, filename);
return -1;
}
memset (new_access_info, '\0', sizeof (new_access_info));
while (fgets (buf, 1024, fd_access_list))
{
char *dbname, *dbuser, *ip_file, *p;
line++;
p = strchr (buf, '#');
if (p != NULL)
{
*p = '\0';
}
trim (buf);
if (buf[0] == '\0')
{
continue;
}
if ((ret = is_invalid_acl_entry (buf, shm_br)))
{
sprintf (admin_err_msg, "%s: invalid acl list entry: (%s:%d)%s", shm_appl->broker_name, filename, line,
ret == ACL_FMT_UNKOWN_BROKER ? " (unknown broker)" : "");
goto error;
}
if (is_current_broker_section == false && strncmp (buf, "[%", 2) == 0 && buf[strlen (buf) - 1] == ']')
{
buf[strlen (buf) - 1] = '\0';
if (strcasecmp (shm_appl->broker_name, buf + 2) == 0)
{
is_current_broker_section = true;
continue;
}
}
if (is_current_broker_section == false)
{
continue;
}
if (strncmp (buf, "[%", 2) == 0 && buf[strlen (buf) - 1] == ']')
{
buf[strlen (buf) - 1] = '\0';
if (strcasecmp (shm_appl->broker_name, buf + 2) != 0)
{
break;
}
}
if (num_access_list >= ACL_MAX_ITEM_COUNT)
{
sprintf (admin_err_msg, "%s: error while loading access control file(%s)" " - max item count(%d) exceeded.",
shm_appl->broker_name, filename, ACL_MAX_ITEM_COUNT);
goto error;
}
dbname = strtok_r (buf, ACCESS_FILE_DELIMITER, &p);
if (dbname == NULL || strlen (dbname) > (ACL_MAX_DBNAME_LENGTH - 1))
{
sprintf (admin_err_msg,
"%s: error while loading access control file(%s:%d)" " - Database name is empty or too long.",
shm_appl->broker_name, filename, line);
goto error;
}
dbuser = strtok_r (NULL, ACCESS_FILE_DELIMITER, &p);
if (dbuser == NULL || strlen (dbuser) > (ACL_MAX_DBUSER_LENGTH - 1))
{
sprintf (admin_err_msg,
"%s: error while loading access control file(%s:%d)" " - Database user is empty or too long.",
shm_appl->broker_name, filename, line);
goto error;
}
ip_file = p;
if (ip_file == NULL)
{
sprintf (admin_err_msg,
"%s: error while loading access control file(%s:%d)" " - IP list file paths are empty.",
shm_appl->broker_name, filename, line);
goto error;
}
access_info = access_control_find_access_info (new_access_info, num_access_list, dbname, dbuser);
if (access_info == NULL)
{
access_info = &new_access_info[num_access_list];
strncpy (access_info->dbname, dbname, ACL_MAX_DBNAME_LENGTH);
strncpy (access_info->dbuser, dbuser, ACL_MAX_DBUSER_LENGTH);
num_access_list++;
}
for (files = ip_file;; files = NULL)
{
token = strtok_r (files, IP_FILE_DELIMITER, &save);
if (token == NULL)
{
break;
}
if (strlen (token) > BROKER_PATH_MAX - 1)
{
snprintf (admin_err_msg, ADMIN_ERR_MSG_SIZE,
"%s: error while loading access control file(%s)" " - a IP file path(%s) is too long",
shm_appl->broker_name, filename, token);
goto error;
}
#if defined (WINDOWS)
if (token[0] == '\\' || token[0] == '/')
{
snprintf (admin_err_msg, ADMIN_ERR_MSG_SIZE,
"%s: error while loading access control file (%s)"
" - when using an absolute path name, the driver name must be specified (%s). ",
shm_appl->broker_name, filename, token);
goto error;
}
#endif
if (make_abs_path (path_buf, "conf", token, BROKER_PATH_MAX) < 0)
{
goto error;
}
if (access_control_read_ip_info (&(access_info->ip_info), path_buf, admin_err_msg) < 0)
{
goto error;
}
if (access_info->ip_files[0] != '\0')
{
if (strlen (access_info->ip_files) < (sizeof (access_info->ip_files) - 1))
{
strcat (access_info->ip_files, ",");
}
else
{
goto error;
}
}
filename_len = strlen (path_buf);
if ((strlen (access_info->ip_files) + filename_len) < sizeof (access_info->ip_files))
{
strcat (access_info->ip_files, path_buf);
}
else
{
goto error;
}
}
}
fclose (fd_access_list);
#if defined (WINDOWS)
MAKE_ACL_SEM_NAME (acl_sem_name, shm_appl->broker_name);
uw_sem_wait (acl_sem_name);
#else
uw_sem_wait (&shm_appl->acl_sem);
#endif
memcpy (shm_appl->access_info, new_access_info, sizeof (new_access_info));
shm_appl->num_access_info = num_access_list;
shm_appl->acl_chn++;
#if defined(WINDOWS)
uw_sem_post (acl_sem_name);
#else
uw_sem_post (&shm_appl->acl_sem);
#endif
return 0;
error:
fclose (fd_access_list);
return -1;
}
static ACL_FMT
is_invalid_acl_entry (const char *acl, T_SHM_BROKER * shm_br)
{
char br_name[LINE_MAX], db[LINE_MAX], user[LINE_MAX], file[LINE_MAX];
int len;
int i;
bool exist = false;
ACL_FMT ret = ACL_FMT_NO_ERROR;
if (acl == NULL || (len = strlen (acl)) == 0)
{
return ACL_FMT_INVALID;;
}
if (acl[0] == '[')
{
if (sscanf (acl, "[%%%[^]]", br_name) != 1 || acl[len - 1] != ']' || strchr (br_name, ' ') != NULL)
{
ret = ACL_FMT_INVALID;
}
else
{
for (i = 0; i < shm_br->num_broker; i++)
{
if (strcasecmp (br_name, shm_br->br_info[i].name) == 0)
{
exist = true;
break;
}
}
ret = exist ? ACL_FMT_NO_ERROR : ACL_FMT_UNKOWN_BROKER;
}
return ret;
}
if (sscanf (acl, "%[^: ]:%[^: ]:%s", db, user, file) != NUM_ACL_ELEM)
{
ret = ACL_FMT_INVALID;
}
return ret;
}
static int
access_control_read_ip_info (IP_INFO * ip_info, char *filename, char *admin_err_msg)
{
char buf[LINE_MAX];
char *save;
FILE *fd_ip_list;
unsigned char i;
unsigned int ln = 0;
fd_ip_list = fopen (filename, "r");
if (fd_ip_list == NULL)
{
sprintf (admin_err_msg, "Could not open ip info file(%s)", filename);
return -1;
}
buf[LINE_MAX - 2] = 0;
while (fgets (buf, LINE_MAX, fd_ip_list))
{
char *token, *p;
int address_index;
ln++;
if (buf[LINE_MAX - 2] != 0 && buf[LINE_MAX - 2] != '\n')
{
sprintf (admin_err_msg, "Error while loading ip info file(%s)" " - %d line is too long", filename, ln);
goto error;
}
p = strchr (buf, '#');
if (p != NULL)
{
*p = '\0';
}
trim (buf);
if (buf[0] == '\0')
{
continue;
}
if (ip_info->num_list >= ACL_MAX_IP_COUNT)
{
sprintf (admin_err_msg, "Error while loading ip info file(%s) line(%d)" " - max ip count(%d) exceeded.",
filename, ln, ACL_MAX_IP_COUNT);
goto error;
}
token = strtok_r (buf, ".", &save);
address_index = ip_info->num_list * IP_BYTE_COUNT;
for (i = 0; i < 4; i++)
{
if (token == NULL)
{
sprintf (admin_err_msg, "Error while loading ip info file(%s) line(%d)", filename, ln);
goto error;
}
if (strcmp (token, "*") == 0)
{
break;
}
else
{
int adr = 0, result;
result = parse_int (&adr, token, 10);
if (result != 0 || adr > 255 || adr < 0)
{
sprintf (admin_err_msg, "Error while loading ip info file(%s) line(%d)", filename, ln);
goto error;
}
ip_info->address_list[address_index + 1 + i] = (unsigned char) adr;
}
token = strtok_r (NULL, ".", &save);
if (i == 3 && token != NULL)
{
sprintf (admin_err_msg, "Error while loading ip info file(%s) line(%d)", filename, ln);
goto error;
}
}
ip_info->address_list[address_index] = i;
ip_info->last_access_time[ip_info->num_list] = 0;
ip_info->num_list++;
}
fclose (fd_ip_list);
return 0;
error:
fclose (fd_ip_list);
return -1;
}
int
access_control_check_right (T_SHM_APPL_SERVER * shm_as_p, char *dbname, char *dbuser, unsigned char *address)
{
if (access_info_changed != shm_as_p->acl_chn)
{
#if defined (WINDOWS)
char acl_sem_name[BROKER_NAME_LEN];
MAKE_ACL_SEM_NAME (acl_sem_name, shm_as_p->broker_name);
uw_sem_wait (acl_sem_name);
#else
uw_sem_wait (&shm_as_p->acl_sem);
#endif
memcpy (access_info, shm_as_p->access_info, sizeof (access_info));
num_access_info = shm_as_p->num_access_info;
access_info_changed = shm_as_p->acl_chn;
#if defined (WINDOWS)
uw_sem_post (acl_sem_name);
#else
uw_sem_post (&shm_as_p->acl_sem);
#endif
}
return (access_control_check_right_internal (shm_as_p, dbname, dbuser, address));
}
static int
access_control_check_right_internal (T_SHM_APPL_SERVER * shm_as_p, char *dbname, char *dbuser, unsigned char *address)
{
int i;
char *address_ptr;
int ret_val = -1;
bool local_ip_flag = false;
// If there is no broker section in the ACL file and acl_default_policy is ALLOW, access is allowed for all IPs.
if (num_access_info == 0 && shm_as_p->acl_default_policy == ALLOW)
{
return 0;
}
if (address[0] == 127 && address[1] == 0 && address[2] == 0 && address[3] == 1)
{
local_ip_flag = true;
}
address_ptr = strchr (dbname, '@');
if (address_ptr != NULL)
{
*address_ptr = '\0';
}
for (i = 0; i < num_access_info; i++)
{
if ((strcmp (access_info[i].dbname, "*") == 0
|| strncasecmp (access_info[i].dbname, dbname, ACL_MAX_DBNAME_LENGTH) == 0)
&& (strcmp (access_info[i].dbuser, "*") == 0
|| strncasecmp (access_info[i].dbuser, dbuser, ACL_MAX_DBUSER_LENGTH) == 0))
{
if (access_control_check_ip (shm_as_p, &access_info[i].ip_info, address, i) == 0)
{
ret_val = 0;
break;
}
if (local_ip_flag == true
&& access_control_check_ip (shm_as_p, &access_info[i].ip_info, shm_as_p->local_ip_addr, i) == 0)
{
break;
}
}
}
if (address_ptr != NULL)
{
*address_ptr = '@';
}
if (local_ip_flag == true)
{
return 0;
}
return ret_val;
}
static int
access_control_check_ip (T_SHM_APPL_SERVER * shm_as_p, IP_INFO * ip_info, unsigned char *address, int info_index)
{
int i;
assert (ip_info && address);
for (i = 0; i < ip_info->num_list; i++)
{
int address_index = i * IP_BYTE_COUNT;
if (ip_info->address_list[address_index] == 0)
{
record_ip_access_time (shm_as_p, info_index, i);
return 0;
}
else
if (memcmp
((void *) &ip_info->address_list[address_index + 1], (void *) address,
ip_info->address_list[address_index]) == 0)
{
record_ip_access_time (shm_as_p, info_index, i);
return 0;
}
}
return -1;
}
static int
record_ip_access_time (T_SHM_APPL_SERVER * shm_as_p, int info_index, int list_index)
{
#if defined (WINDOWS)
char acl_sem_name[BROKER_NAME_LEN];
#endif
if (access_info_changed != shm_as_p->acl_chn)
{
return -1;
}
#if defined (WINDOWS)
MAKE_ACL_SEM_NAME (acl_sem_name, shm_as_p->broker_name);
uw_sem_wait (acl_sem_name);
#else
uw_sem_wait (&shm_as_p->acl_sem);
#endif
shm_as_p->access_info[info_index].ip_info.last_access_time[list_index] = time (NULL);
#if defined (WINDOWS)
uw_sem_post (acl_sem_name);
#else
uw_sem_post (&shm_as_p->acl_sem);
#endif
return 0;
}