PostgreSQL Source Code  git master
saslprep.h File Reference
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Enumerations

enum  pg_saslprep_rc { SASLPREP_SUCCESS = 0, SASLPREP_OOM = -1, SASLPREP_INVALID_UTF8 = -2, SASLPREP_PROHIBITED = -3 }
 

Functions

pg_saslprep_rc pg_saslprep (const char *input, char **output)
 

Enumeration Type Documentation

◆ pg_saslprep_rc

Enumerator
SASLPREP_SUCCESS 
SASLPREP_OOM 
SASLPREP_INVALID_UTF8 
SASLPREP_PROHIBITED 

Definition at line 20 of file saslprep.h.

21 {
22  SASLPREP_SUCCESS = 0,
23  SASLPREP_OOM = -1, /* out of memory (only in frontend) */
24  SASLPREP_INVALID_UTF8 = -2, /* input is not a valid UTF-8 string */
25  SASLPREP_PROHIBITED = -3 /* output would contain prohibited characters */
pg_saslprep_rc
Definition: saslprep.h:20

Function Documentation

◆ pg_saslprep()

pg_saslprep_rc pg_saslprep ( const char *  input,
char **  output 
)

Definition at line 1071 of file saslprep.c.

References ALLOC, Assert, buf, commonly_mapped_to_nothing_ranges, ereport, errcode(), errmsg(), ERROR, FREE, i, IS_CODE_IN_TABLE, LCat_codepoint_ranges, MAX_PASSWORD_LENGTH, non_ascii_space_ranges, pg_is_ascii_string(), pg_utf8_string_len(), pg_utf_mblen(), prohibited_output_ranges, RandALCat_codepoint_ranges, SASLPREP_INVALID_UTF8, SASLPREP_OOM, SASLPREP_PROHIBITED, SASLPREP_SUCCESS, STRDUP, unassigned_codepoint_ranges, unicode_normalize_kc(), unicode_to_utf8(), and utf8_to_unicode().

Referenced by pg_be_scram_build_secret(), pg_fe_scram_build_secret(), pg_fe_scram_init(), and scram_verify_plain_password().

1072 {
1073  pg_wchar *input_chars = NULL;
1074  pg_wchar *output_chars = NULL;
1075  int input_size;
1076  char *result;
1077  int result_size;
1078  int count;
1079  int i;
1080  bool contains_RandALCat;
1081  unsigned char *p;
1082  pg_wchar *wp;
1083 
1084  /* Ensure we return *output as NULL on failure */
1085  *output = NULL;
1086 
1087  /* Check that the password isn't stupendously long */
1088  if (strlen(input) > MAX_PASSWORD_LENGTH)
1089  {
1090 #ifndef FRONTEND
1091  ereport(ERROR,
1092  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1093  errmsg("password too long")));
1094 #else
1095  return SASLPREP_OOM;
1096 #endif
1097  }
1098 
1099  /*
1100  * Quick check if the input is pure ASCII. An ASCII string requires no
1101  * further processing.
1102  */
1103  if (pg_is_ascii_string(input))
1104  {
1105  *output = STRDUP(input);
1106  if (!(*output))
1107  goto oom;
1108  return SASLPREP_SUCCESS;
1109  }
1110 
1111  /*
1112  * Convert the input from UTF-8 to an array of Unicode codepoints.
1113  *
1114  * This also checks that the input is a legal UTF-8 string.
1115  */
1116  input_size = pg_utf8_string_len(input);
1117  if (input_size < 0)
1118  return SASLPREP_INVALID_UTF8;
1119 
1120  input_chars = ALLOC((input_size + 1) * sizeof(pg_wchar));
1121  if (!input_chars)
1122  goto oom;
1123 
1124  p = (unsigned char *) input;
1125  for (i = 0; i < input_size; i++)
1126  {
1127  input_chars[i] = utf8_to_unicode(p);
1128  p += pg_utf_mblen(p);
1129  }
1130  input_chars[i] = (pg_wchar) '\0';
1131 
1132  /*
1133  * The steps below correspond to the steps listed in [RFC3454], Section
1134  * "2. Preparation Overview"
1135  */
1136 
1137  /*
1138  * 1) Map -- For each character in the input, check if it has a mapping
1139  * and, if so, replace it with its mapping.
1140  */
1141  count = 0;
1142  for (i = 0; i < input_size; i++)
1143  {
1144  pg_wchar code = input_chars[i];
1145 
1147  input_chars[count++] = 0x0020;
1149  {
1150  /* map to nothing */
1151  }
1152  else
1153  input_chars[count++] = code;
1154  }
1155  input_chars[count] = (pg_wchar) '\0';
1156  input_size = count;
1157 
1158  if (input_size == 0)
1159  goto prohibited; /* don't allow empty password */
1160 
1161  /*
1162  * 2) Normalize -- Normalize the result of step 1 using Unicode
1163  * normalization.
1164  */
1165  output_chars = unicode_normalize_kc(input_chars);
1166  if (!output_chars)
1167  goto oom;
1168 
1169  /*
1170  * 3) Prohibit -- Check for any characters that are not allowed in the
1171  * output. If any are found, return an error.
1172  */
1173  for (i = 0; i < input_size; i++)
1174  {
1175  pg_wchar code = input_chars[i];
1176 
1178  goto prohibited;
1180  goto prohibited;
1181  }
1182 
1183  /*
1184  * 4) Check bidi -- Possibly check for right-to-left characters, and if
1185  * any are found, make sure that the whole string satisfies the
1186  * requirements for bidirectional strings. If the string does not satisfy
1187  * the requirements for bidirectional strings, return an error.
1188  *
1189  * [RFC3454], Section "6. Bidirectional Characters" explains in more
1190  * detail what that means:
1191  *
1192  * "In any profile that specifies bidirectional character handling, all
1193  * three of the following requirements MUST be met:
1194  *
1195  * 1) The characters in section 5.8 MUST be prohibited.
1196  *
1197  * 2) If a string contains any RandALCat character, the string MUST NOT
1198  * contain any LCat character.
1199  *
1200  * 3) If a string contains any RandALCat character, a RandALCat character
1201  * MUST be the first character of the string, and a RandALCat character
1202  * MUST be the last character of the string."
1203  */
1204  contains_RandALCat = false;
1205  for (i = 0; i < input_size; i++)
1206  {
1207  pg_wchar code = input_chars[i];
1208 
1210  {
1211  contains_RandALCat = true;
1212  break;
1213  }
1214  }
1215 
1216  if (contains_RandALCat)
1217  {
1218  pg_wchar first = input_chars[0];
1219  pg_wchar last = input_chars[input_size - 1];
1220 
1221  for (i = 0; i < input_size; i++)
1222  {
1223  pg_wchar code = input_chars[i];
1224 
1226  goto prohibited;
1227  }
1228 
1231  goto prohibited;
1232  }
1233 
1234  /*
1235  * Finally, convert the result back to UTF-8.
1236  */
1237  result_size = 0;
1238  for (wp = output_chars; *wp; wp++)
1239  {
1240  unsigned char buf[4];
1241 
1242  unicode_to_utf8(*wp, buf);
1243  result_size += pg_utf_mblen(buf);
1244  }
1245 
1246  result = ALLOC(result_size + 1);
1247  if (!result)
1248  goto oom;
1249 
1250  /*
1251  * There are no error exits below here, so the error exit paths don't need
1252  * to worry about possibly freeing "result".
1253  */
1254  p = (unsigned char *) result;
1255  for (wp = output_chars; *wp; wp++)
1256  {
1257  unicode_to_utf8(*wp, p);
1258  p += pg_utf_mblen(p);
1259  }
1260  Assert((char *) p == result + result_size);
1261  *p = '\0';
1262 
1263  FREE(input_chars);
1264  FREE(output_chars);
1265 
1266  *output = result;
1267  return SASLPREP_SUCCESS;
1268 
1269 prohibited:
1270  if (input_chars)
1271  FREE(input_chars);
1272  if (output_chars)
1273  FREE(output_chars);
1274 
1275  return SASLPREP_PROHIBITED;
1276 
1277 oom:
1278  if (input_chars)
1279  FREE(input_chars);
1280  if (output_chars)
1281  FREE(output_chars);
1282 
1283  return SASLPREP_OOM;
1284 }
static const pg_wchar commonly_mapped_to_nothing_ranges[]
Definition: saslprep.c:93
#define ALLOC(size)
Definition: saslprep.c:50
static const pg_wchar prohibited_output_ranges[]
Definition: saslprep.c:128
pg_wchar utf8_to_unicode(const unsigned char *c)
Definition: wchar.c:751
unsigned char * unicode_to_utf8(pg_wchar c, unsigned char *utf8string)
Definition: wchar.c:482
static int pg_utf8_string_len(const char *source)
Definition: saslprep.c:1014
static void output(uint64 loop_count)
static const pg_wchar non_ascii_space_ranges[]
Definition: saslprep.c:78
#define STRDUP(s)
Definition: saslprep.c:49
#define MAX_PASSWORD_LENGTH
Definition: saslprep.c:42
int errcode(int sqlerrcode)
Definition: elog.c:608
static const pg_wchar unassigned_codepoint_ranges[]
Definition: saslprep.c:169
#define ERROR
Definition: elog.h:43
#define IS_CODE_IN_TABLE(code, map)
Definition: saslprep.c:977
static char * buf
Definition: pg_test_fsync.c:67
#define ereport(elevel, rest)
Definition: elog.h:141
unsigned int pg_wchar
Definition: mbprint.c:31
static bool pg_is_ascii_string(const char *p)
Definition: saslprep.c:1038
static const pg_wchar LCat_codepoint_ranges[]
Definition: saslprep.c:609
pg_wchar * unicode_normalize_kc(const pg_wchar *input)
Definition: unicode_norm.c:307
#define Assert(condition)
Definition: c.h:739
int pg_utf_mblen(const unsigned char *s)
Definition: wchar.c:548
int errmsg(const char *fmt,...)
Definition: elog.c:822
int i
static const pg_wchar RandALCat_codepoint_ranges[]
Definition: saslprep.c:570
#define FREE(size)
Definition: saslprep.c:51