Skip to content

File hide_password.cpp

File List > base > hide_password.cpp

Go to the documentation of this file

/*
 *
 * 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.
 *
 */


/*
 * hide_password.cpp -
 */

#ident "$Id$"

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <errno.h>
#if defined(WINDOWS)
#include <sys/timeb.h>
#include <process.h>
#include <io.h>
#else
#include <unistd.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <signal.h>
#endif
#include <assert.h>

#include "porting.h"
#include "cas_common.h"
#include "hide_password.h"
#include "system_parameter.h"
#include "chartype.h"

//==========================================================================
#define SKIP_SPACE_CHARACTERS(p)                \
  do {                                          \
        while (char_isspace((unsigned char) *p))\
        {                                   \
          p++;                              \
        }                                   \
   } while(0)

#define MAX_PWD_LENGTH                     (0x0FFFFFFF)
#define SET_PWD_LENGTH(s, e)               ((e) - (s))
#define SET_PWD_ADDINFO(comma, en_pwd)     (((comma) ? (0x01 << 30) : 0) | (((en_pwd) & 0x03) << 28))
#define SET_PWD_LENGTH_N_ADDINFO(s, e, comma, en_pwd)  (SET_PWD_ADDINFO((comma), (en_pwd)) | SET_PWD_LENGTH((s), (e)))
#define IS_PWD_NEED_COMMA(pwd_info_ptr)    (((pwd_info_ptr)[1] >> 30) & 0x01)
#define IS_PWD_NEED_PASSWORD(pwd_info_ptr) ((EN_ADD_PWD_STRING)(((pwd_info_ptr)[1] >> 28) & 0x03))
#define GET_END_PWD_OFFSET(pwd_info_ptr)   ((pwd_info_ptr)[0] + ((pwd_info_ptr)[1] & MAX_PWD_LENGTH))

class hide_password
{
  private:
    char *skip_comment_string (char *query);
    char *find_end_of_quot (char *ps);
    char *get_token (char *&in, int &len);
    char *get_method_passowrd_start_position (char *ps, char *method_name, int *method_password_len);
    char *get_passowrd_pos_n_len (char *query, bool is_create, bool is_server, int *password_len,
                  bool *is_pwd_keyword_found);
    char *skip_one_query (char *query);
    bool check_lead_string_in_query (char **query, char **method_name, bool *is_create, bool *is_server);
    void fprintf_replace_newline (FILE *fp, char *query, int (*cas_fprintf) (FILE *, const char *, ...));
    bool check_capitalized_keyword_create (char *query);
    const char *get_password_string (char *qryptr, int *pwd_info_ptr);

    bool  m_use_backslash_escape;

  public:
    hide_password ()
    {
      m_use_backslash_escape = ! prm_get_bool_value (PRM_ID_NO_BACKSLASH_ESCAPES);
    };
    ~hide_password ()
    {
    };

    void find_password_positions (char *query, HIDE_PWD_INFO_PTR hide_pwd_ptr);
    int snprint_password (char *msg, int size, char *query, HIDE_PWD_INFO_PTR hide_pwd_ptr);
    void fprintf_password (FILE *fp, char *query, HIDE_PWD_INFO_PTR hide_pwd_ptr,
               int (*cas_fprintf) (FILE *, const char *, ...));
};

char *
hide_password::skip_comment_string (char *query)
{
  query += 2;
  if (query[-1] != '*')
    {
      // case) -- or //
      while (*query)
    {
      if (*query == '\n')
        {
          query++;
          break;
        }
      query++;
    }
    }
  else
    {
      // case)  /*
      while (*query)
    {
      if (*query == '*' && query[1] == '/')
        {
          query += 2;
          break;
        }
      query++;
    }
    }
  return query;
}

char *
hide_password::find_end_of_quot (char *ps)
{
  char quot_char = *ps;

  for (ps++; *ps; ps++)
    {
      if (*ps == '\\' && m_use_backslash_escape)
    {
      ps++;
    }
      else if (*ps == quot_char)
    {
      ps++;
      return ps;
    }
    }
  return ps;
}

char *
hide_password::get_token (char *&in, int &len)
{
  char *ps, check_char;
  int quoted_single = 0;
  int quoted_double = 0;

  SKIP_SPACE_CHARACTERS (in);
  ps = in;
  if (*in == '\'' || *in == '"')
    {
      in = find_end_of_quot (in);
      len = (int) (in - ps);
      return ps;
    }

  while (*in)
    {
      switch (*in)
    {
    case '=':
    case ',':
    case '(':
    case ')':
    case ';':
    case '\'':
    case '"':
      if (ps == in)
        {
          in++;
        }
      len = (int) (in - ps);
      return ps;

    case '-':
    case '/':
      if (in[0] == in[1])
        {
          in = skip_comment_string (in);
        }
      else if (in[0] == '/' && in[1] == '*')
        {
          in = skip_comment_string (in);
        }
      break;

    default:
      if (char_isspace ((unsigned char) *in))
        {
          len = (int) (in - ps);
          return ps;
        }
      break;
    }

      in++;
    }

  if (in == ps)
    {
      return NULL;
    }

  len = (int) (in - ps);
  return ps;
}

char *
hide_password::get_method_passowrd_start_position (char *ps, char *method_name, int *method_password_len)
{
  /*
     set_password('password_string')
     add_user ('user_name', 'password_string')
     add_user ('user_name')
     login ('user_name')
     login ('user_name', 'password')
   */
  int len;
  char *token;

  *method_password_len = -1;
  token = get_token (ps, len);
  if (len != 1 || *token != '(')
    {
      return NULL;
    }

  if (strcasecmp (method_name, "set_password") == 0)
    {
      token = get_token (ps, len);  // read user_name
      if (len >= 2 && (*token == '\'' || *token == '"'))
    {
      *method_password_len = len;
      return token;
    }
    }
  else
    {
      token = get_token (ps, len);  // read user_name
      if (len < 2 || (*token != '\'' && *token != '"'))
    {
      return NULL;
    }

      token = get_token (ps, len);
      if (len == 1)
    {
      if (*token == ')')
        {
          *method_password_len = 0;
          return token;
        }
      else if (*token == ',')
        {
          token = get_token (ps, len);  // read password
          if (len >= 2 && (*token == '\'' || *token == '"'))
        {
          *method_password_len = len;
          return token;
        }
        }
    }
    }

  return NULL;
}


char *
hide_password::get_passowrd_pos_n_len (char *query, bool is_create, bool is_server, int *password_len,
                       bool *is_pwd_keyword_found)
{
  char *ps = query;
  char *token, *prev;
  int len, tlen = 0;
  bool is_open = false;

  /* pattern cases to consider)
  * CREATE SERVER srv1 (HOST='localhost', PORT=3300, DBNAME=demodb, USER=dev1, PASSWORD='password_string')
  * CREATE SERVER srv1 (HOST='localhost', PORT=3300, DBNAME=demodb, USER=dev1, PASSWORD=)
  * CREATE SERVER srv1 (HOST='localhost', PORT=3300, DBNAME=demodb, USER=dev1, PASSWORD='')
  * CREATE SERVER srv1 (HOST='localhost', PORT=3300, DBNAME=demodb, PASSWORD=, USER=dev1)
  * CREATE SERVER srv1 (HOST='localhost', PORT=3300, DBNAME=demodb, USER=dev1)
  *
  * CREATE USER user_name
  * CREATE USER user_name PASSWORD 'password_string'
  * CREATE USER user_name PASSWORD _utf8'password_string'
  * CREATE USER user_name PASSWORD _euckr'password_string'
  * ALTER USER user_name PASSWORD 'password_string'
  * ALTER SERVER srv1 CHANGE PASSWORD='password string'
  */

  *password_len = 0;
  *is_pwd_keyword_found = false;
  while (*ps)
    {
      token = get_token (ps, len);
      if (*token == ';' || *token == ')')
    {
      return token;
    }

      if (len == 8 && strncasecmp (token, "password", 8) == 0)
    {
      *is_pwd_keyword_found = true;
      break;
    }
    }

  if (*ps == '\0')
    {
      // check case "CREATE USER user_name"
      return (is_create && !is_server) ? ps : NULL;
    }

  prev = NULL;
  token = get_token (ps, len);
  if (is_server)
    {
      /* pattern cases)
         *    PASSWORD = 'string'   PASSWORD = ''    PASSWORD = )
         *    PASSWORD = ,          PASSWORD = ;     PASSWORD = \0
        */
      if (*token != '=')
    {
      return NULL;
    }

      token = get_token (ps, len);
      if (*token == ';' || *token == ')' || *token == ',' )
    {
      return token;
    }
    }
  else if (*token == '_')
    {
      prev = token;
      tlen = len;
      if ((len == 5 && strncasecmp (token + 1, "utf8'", len) == 0)
      || (len == 6 && strncasecmp (token + 1, "euckr'", len) == 0)
      || (len == 9 && strncasecmp (token + 1, "iso88591'", len) == 0)
      || (len == 7 && strncasecmp (token + 1, "binary'", len) == 0))
    {
      token = get_token (ps, len);
    }
      else
    {
      return NULL;
    }
    }

  if (len >= 2 && (*token == '\'' || *token == '"'))
    {
      *password_len = (prev ? (len + tlen) : len);
      return (prev ? prev : token);
    }

  return NULL;
}

char *
hide_password::skip_one_query (char *query)
{
  char *ps;

  for (ps = query; *ps; ps++)
    {
      if (*ps == '\'' || *ps == '"')
    {
      ps = find_end_of_quot (ps);
      if (*ps == '\0')
        {
          break;
        }
    }
      else if (*ps == '-')
    {
      if (ps[1] == '-')
        {
          ps = skip_comment_string (ps);
        }
    }
      else if (*ps == '/')
    {
      if (ps[1] == '/' || ps[1] == '*')
        {
          ps = skip_comment_string (ps);
        }
    }
      else if (*ps == ';')
    {
      ps++;
      break;
    }
    }

  return ps;
}

bool hide_password::check_lead_string_in_query (char **query, char **method_name, bool *is_create, bool *is_server)
{
#define IDX_CALL_STMT   (0)
#define IDX_CREATE_STMT (1)
#define IDX_SERVER_STMT (0)
  static const char *first_cmd_str[] = { "call", "create", "alter", NULL };  //
  int  first_cmd_len[] = { 4, 6, 5, -1 };  // first_cmd_len[idx] = strlen(first_cmd_str[idx])
  static const char *second_cmd_str[] = { "server", "user", NULL };
  int  second_cmd_len[] = { 6, 4, -1 };    // second_cmd_len[idx] = strlen(second_cmd_str[idx])
  static const char *method_name_str[] = { "add_user", "set_password", "login", NULL };
  int method_name_len[] = { 8, 12, 5, -1 };
  bool  is_call_stmt = false;
  int *len_ptr = NULL;
  char **str_ptr = NULL;

  char *token, *ps;
  int len, i;

  *is_create = false;
  *is_server = false;

  token = get_token (*query, len);
  if (!token)
    {
      return false;
    }

  for ( i = 0; first_cmd_str[i]; i++)
    {
      if (first_cmd_len[i] == len && strncasecmp (token, first_cmd_str[i], first_cmd_len[i]) == 0)
    {
      if (i == IDX_CALL_STMT)
        {
          is_call_stmt = true;
          len_ptr = method_name_len;
          str_ptr = (char **)method_name_str;
        }
      else
        {
          *is_create = (i == IDX_CREATE_STMT) ? true : false;
          len_ptr = second_cmd_len;
          str_ptr = (char **)second_cmd_str;
        }
      break;
    }
    }

  if (first_cmd_str[i] == NULL || (*query)[0] == '\0')
    {
      return false;
    }

  assert (len_ptr && str_ptr);

  token = get_token (*query, len);
  if (token)
    {
      for ( i = 0; str_ptr[i]; i++)
    {
      if (len_ptr[i] == len && strncasecmp (token, str_ptr[i], len_ptr[i]) == 0)
        {
          if (is_call_stmt)
        {
          *method_name = (char *) str_ptr[i];
        }
          else
        {
          *is_server = (i == IDX_SERVER_STMT) ? true : false;
        }
          return true;
        }
    }
    }

  return false;
}

void
hide_password::find_password_positions (char *query, HIDE_PWD_INFO_PTR hide_pwd_ptr)
{
  int start, end;
  bool is_add_comma;
  bool is_create, is_server, has_password_keyword;
  char *newptr = query;
  EN_ADD_PWD_STRING en_add_pwd_string = en_none_password;

  assert (hide_pwd_ptr != NULL);
  assert (hide_pwd_ptr->pwd_info_ptr != NULL);

  while (*newptr)
    {
      char *tp, *ps;
      int password_len;
      char *method_name = NULL;

      if (check_lead_string_in_query (&newptr, &method_name, &is_create, &is_server))
    {
      if (method_name)
        {
          if ((ps = get_method_passowrd_start_position (newptr, method_name, &password_len)) == NULL)
        {
          newptr = skip_one_query (newptr);
          continue;
        }

          start = (int) (ps - query);
          end = (int) (ps - query) + password_len;
          is_add_comma = (bool) (password_len == 0);
          en_add_pwd_string = en_none_password;
          newptr = ps + password_len;
        }
      else
        {
          if ((ps = get_passowrd_pos_n_len (newptr, is_create, is_server, &password_len, &has_password_keyword)) == NULL)
        {
          newptr = skip_one_query (newptr);
          continue;
        }

          start = (int) (ps - query);
          end = (int) (ps - query) + password_len;
          en_add_pwd_string = (is_create
                   && !has_password_keyword) ? (is_server ? en_server_password : en_user_password) : en_none_password;
          is_add_comma = (bool) (is_create && is_server && !has_password_keyword);

          newptr = ps + password_len;
        }

      if (hide_pwd_ptr->size < (hide_pwd_ptr->used + 2))
        {
          int *pwd_info_ptr = NULL;
          int new_size = hide_pwd_ptr->size + (DEFAULT_PWD_INFO_CNT * 2);

          pwd_info_ptr = (int *) malloc (new_size * sizeof (int));
          if (!pwd_info_ptr)
        {
          assert (0);
          return;
        }

          memcpy (pwd_info_ptr, hide_pwd_ptr->pwd_info_ptr, hide_pwd_ptr->used * sizeof (int));
          if (hide_pwd_ptr->pwd_info_ptr != hide_pwd_ptr->pwd_info)
        {
          free (hide_pwd_ptr->pwd_info_ptr);
        }

          hide_pwd_ptr->size = new_size;
          hide_pwd_ptr->pwd_info_ptr = pwd_info_ptr;
        }

      assert (SET_PWD_LENGTH (start, end) < MAX_PWD_LENGTH);
      hide_pwd_ptr->pwd_info_ptr[hide_pwd_ptr->used++] = start;
      hide_pwd_ptr->pwd_info_ptr[hide_pwd_ptr->used++] = SET_PWD_LENGTH_N_ADDINFO (start, end, is_add_comma,
          en_add_pwd_string);
    }

      newptr = skip_one_query (newptr);
    }
}

bool
hide_password::check_capitalized_keyword_create (char *query)
{
  char *ps = query;
  int len;
  char *token;

  // "create user ~" or " ~; create user ~"
  token = get_token (ps, len);
  if ((len == 6) &&  (strncmp (token, "CREATE", len) == 0))
    {
      return true;
    }
  return false;
}

const char *
hide_password::get_password_string (char *qryptr, int *pwd_info_ptr)
{
  EN_ADD_PWD_STRING en_pwd_string;
  // *INDENT-OFF*
  static const char* password_string[6] = { 
        ", '****'" ,          " '****'",
        " PASSWORD '****'" ,  " password '****'",
        ", PASSWORD='****'" , " password='****'"
  };
  // *INDENT-ON*

  en_pwd_string = IS_PWD_NEED_PASSWORD (pwd_info_ptr);
  if (en_pwd_string == en_none_password)
    {
      return (IS_PWD_NEED_COMMA (pwd_info_ptr) ? password_string[0] : password_string[1]);
    }
  else
    {
      bool is_capatalized = check_capitalized_keyword_create (qryptr);

      if (en_pwd_string == en_user_password)
    {
      return (is_capatalized ? password_string[2] : password_string[3]);
    }
      else
    {
      assert (en_pwd_string == en_server_password);
      return (is_capatalized ? password_string[4] : password_string[5]);
    }
    }
}

int
hide_password::snprint_password (char *msg, int size, char *query, HIDE_PWD_INFO_PTR hide_pwd_ptr)
{
  char *qryptr = query;
  char chbk;
  int pos;
  int length = 0;

  assert (hide_pwd_ptr);
  int *pwd_info_ptr = hide_pwd_ptr->pwd_info_ptr;

  for (int x = 0; x < hide_pwd_ptr->used; x += 2)
    {
      pos = pwd_info_ptr[x];
      chbk = query[pos];
      query[pos] = '\0';

      length += snprintf (msg + length, size - length, "%s", qryptr);
      length += snprintf (msg + length, size - length, "%s", get_password_string (qryptr, pwd_info_ptr + x));

      query[pos] = chbk;
      qryptr = query + GET_END_PWD_OFFSET (pwd_info_ptr + x);
    }

  if (*qryptr)
    {
      length += snprintf (msg + length, size - length, "%s", qryptr);
    }

  return length;
}

void
hide_password::fprintf_replace_newline (FILE *fp, char *query, int (*cas_fprintf) (FILE *, const char *, ...))
{
  int offset;
  char chbk;

  assert (fp != NULL);

  while (*query)
    {
      offset = strcspn (query, "\r\n");
      if (offset <= 0)
    {
      cas_fprintf (fp, " ");
      query++;
    }
      else
    {
      chbk = query[offset];
      query[offset] = '\0';
      cas_fprintf (fp, "%s", query);
      query[offset] = chbk;
      query += offset;
    }
    }
}

void
hide_password::fprintf_password (FILE *fp, char *query, HIDE_PWD_INFO_PTR hide_pwd_ptr,
                 int (*cas_fprintf) (FILE *, const char *, ...))
{
  char *qryptr = query;
  char chbk;
  int pos;

  assert (hide_pwd_ptr);
  assert (fp != NULL);

  int *pwd_info_ptr = hide_pwd_ptr->pwd_info_ptr;

  for (int x = 0; x < hide_pwd_ptr->used; x += 2)
    {
      pos = pwd_info_ptr[x];
      chbk = query[pos];
      query[pos] = '\0';

      fprintf_replace_newline (fp, qryptr, cas_fprintf);
      cas_fprintf (fp, "%s",  get_password_string (qryptr, pwd_info_ptr + x));

      query[pos] = chbk;
      qryptr = query + GET_END_PWD_OFFSET (pwd_info_ptr + x);
    }

  if (*qryptr)
    {
      fprintf_replace_newline (fp, qryptr, cas_fprintf);
    }
}

void
password_fprintf (FILE *fp, char *query, HIDE_PWD_INFO_PTR hide_pwd_info_ptr,
          int (*cas_fprintf) (FILE *, const char *, ...))
{
  hide_password chp;

  if (hide_pwd_info_ptr && hide_pwd_info_ptr->pwd_info_ptr)
    {
      chp.fprintf_password (fp, query, hide_pwd_info_ptr, cas_fprintf);
    }
  else
    {
      HIDE_PWD_INFO t_pwd_info;

      INIT_HIDE_PASSWORD_INFO (&t_pwd_info);
      chp.find_password_positions (query, &t_pwd_info);
      chp.fprintf_password (fp, query, &t_pwd_info, cas_fprintf);
      QUIT_HIDE_PASSWORD_INFO (&t_pwd_info);
    }
}

int
password_snprint (char *msg, int size, char *query, HIDE_PWD_INFO_PTR hide_pwd_info_ptr)
{
  hide_password chp;
  int ret;

  if (hide_pwd_info_ptr && hide_pwd_info_ptr->pwd_info_ptr)
    {
      ret = chp.snprint_password (msg, size, query, hide_pwd_info_ptr);
    }
  else
    {
      HIDE_PWD_INFO t_pwd_info;

      INIT_HIDE_PASSWORD_INFO (&t_pwd_info);
      chp.find_password_positions (query, &t_pwd_info);
      ret = chp.snprint_password (msg, size, query, &t_pwd_info);
      QUIT_HIDE_PASSWORD_INFO (&t_pwd_info);
    }

  return ret;
}

/*
 * password_add_offset () -
 *   hide_pwd_info_ptr(in/out):
 *   start(in)
 *   end(in)
 *   is_add_comma(in)
 *   en_add_pwd_string(in)
 *   return:
 */
void
password_add_offset (HIDE_PWD_INFO_PTR hide_pwd_info_ptr, int start, int end, bool is_add_comma,
             EN_ADD_PWD_STRING en_add_pwd_string)
{
  assert (hide_pwd_info_ptr);

  /* hide_pwd_info_ptr->pwd_info_ptr:
   * [even] : Start offset of password
   * [odd] : Length of the password string(Including the need for comma)
   */

  if (hide_pwd_info_ptr->size < (hide_pwd_info_ptr->used + 2))
    {
      int *pwd_info_ptr = NULL;
      int new_size = hide_pwd_info_ptr->size + (DEFAULT_PWD_INFO_CNT * 2);

      pwd_info_ptr = (int *) malloc (new_size * sizeof (int));
      if (!pwd_info_ptr)
    {
      assert (0);
      return;
    }

      memcpy (pwd_info_ptr, hide_pwd_info_ptr->pwd_info_ptr, hide_pwd_info_ptr->used * sizeof (int));
      if (hide_pwd_info_ptr->pwd_info_ptr != hide_pwd_info_ptr->pwd_info)
    {
      free (hide_pwd_info_ptr->pwd_info_ptr);
    }

      hide_pwd_info_ptr->size = new_size;
      hide_pwd_info_ptr->pwd_info_ptr = pwd_info_ptr;
    }

  assert (SET_PWD_LENGTH (start, end) < MAX_PWD_LENGTH);
  hide_pwd_info_ptr->pwd_info_ptr[hide_pwd_info_ptr->used++] = start;
  hide_pwd_info_ptr->pwd_info_ptr[hide_pwd_info_ptr->used++] = SET_PWD_LENGTH_N_ADDINFO (start, end, is_add_comma,
      en_add_pwd_string);
}

bool
password_remake_offset_for_one_query (HIDE_PWD_INFO_PTR new_hide_pwd_info_ptr, HIDE_PWD_INFO_PTR orig_hide_pwd_info_ptr,
                      int start_pos, int end_pos)
{
  int *new_pwd_info_ptr = (new_hide_pwd_info_ptr ? new_hide_pwd_info_ptr->pwd_info_ptr : NULL);
  int *orig_pwd_info_ptr = (orig_hide_pwd_info_ptr ? orig_hide_pwd_info_ptr->pwd_info_ptr : NULL);

  assert (new_pwd_info_ptr);
  assert (new_hide_pwd_info_ptr);
  assert (new_hide_pwd_info_ptr->used == 0);

  if (orig_pwd_info_ptr)
    {
      for (int x = 0; x < orig_hide_pwd_info_ptr->used; x += 2)
    {
      if (orig_pwd_info_ptr[x] > end_pos)
        {
          break;
        }

      if (orig_pwd_info_ptr[x] >= start_pos && orig_pwd_info_ptr[x] <= end_pos)
        {
          new_pwd_info_ptr[new_hide_pwd_info_ptr->used++] = orig_pwd_info_ptr[x] - start_pos;
          new_pwd_info_ptr[new_hide_pwd_info_ptr->used++] = orig_pwd_info_ptr[x + 1];
          return true;
        }
    }
    }
  return false;
}