PostgreSQL Source Code  git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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:21
@ SASLPREP_INVALID_UTF8
Definition: saslprep.h:24
@ SASLPREP_PROHIBITED
Definition: saslprep.h:25
@ SASLPREP_OOM
Definition: saslprep.h:23
@ SASLPREP_SUCCESS
Definition: saslprep.h:22

Function Documentation

◆ pg_saslprep()

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

Definition at line 1047 of file saslprep.c.

1048 {
1049  pg_wchar *input_chars = NULL;
1050  pg_wchar *output_chars = NULL;
1051  int input_size;
1052  char *result;
1053  int result_size;
1054  int count;
1055  int i;
1056  bool contains_RandALCat;
1057  unsigned char *p;
1058  pg_wchar *wp;
1059 
1060  /* Ensure we return *output as NULL on failure */
1061  *output = NULL;
1062 
1063  /*
1064  * Quick check if the input is pure ASCII. An ASCII string requires no
1065  * further processing.
1066  */
1067  if (pg_is_ascii(input))
1068  {
1069  *output = STRDUP(input);
1070  if (!(*output))
1071  goto oom;
1072  return SASLPREP_SUCCESS;
1073  }
1074 
1075  /*
1076  * Convert the input from UTF-8 to an array of Unicode codepoints.
1077  *
1078  * This also checks that the input is a legal UTF-8 string.
1079  */
1080  input_size = pg_utf8_string_len(input);
1081  if (input_size < 0)
1082  return SASLPREP_INVALID_UTF8;
1083  if (input_size >= MaxAllocSize / sizeof(pg_wchar))
1084  goto oom;
1085 
1086  input_chars = ALLOC((input_size + 1) * sizeof(pg_wchar));
1087  if (!input_chars)
1088  goto oom;
1089 
1090  p = (unsigned char *) input;
1091  for (i = 0; i < input_size; i++)
1092  {
1093  input_chars[i] = utf8_to_unicode(p);
1094  p += pg_utf_mblen(p);
1095  }
1096  input_chars[i] = (pg_wchar) '\0';
1097 
1098  /*
1099  * The steps below correspond to the steps listed in [RFC3454], Section
1100  * "2. Preparation Overview"
1101  */
1102 
1103  /*
1104  * 1) Map -- For each character in the input, check if it has a mapping
1105  * and, if so, replace it with its mapping.
1106  */
1107  count = 0;
1108  for (i = 0; i < input_size; i++)
1109  {
1110  pg_wchar code = input_chars[i];
1111 
1113  input_chars[count++] = 0x0020;
1115  {
1116  /* map to nothing */
1117  }
1118  else
1119  input_chars[count++] = code;
1120  }
1121  input_chars[count] = (pg_wchar) '\0';
1122  input_size = count;
1123 
1124  if (input_size == 0)
1125  goto prohibited; /* don't allow empty password */
1126 
1127  /*
1128  * 2) Normalize -- Normalize the result of step 1 using Unicode
1129  * normalization.
1130  */
1131  output_chars = unicode_normalize(UNICODE_NFKC, input_chars);
1132  if (!output_chars)
1133  goto oom;
1134 
1135  /*
1136  * 3) Prohibit -- Check for any characters that are not allowed in the
1137  * output. If any are found, return an error.
1138  */
1139  for (i = 0; i < input_size; i++)
1140  {
1141  pg_wchar code = input_chars[i];
1142 
1144  goto prohibited;
1146  goto prohibited;
1147  }
1148 
1149  /*
1150  * 4) Check bidi -- Possibly check for right-to-left characters, and if
1151  * any are found, make sure that the whole string satisfies the
1152  * requirements for bidirectional strings. If the string does not satisfy
1153  * the requirements for bidirectional strings, return an error.
1154  *
1155  * [RFC3454], Section "6. Bidirectional Characters" explains in more
1156  * detail what that means:
1157  *
1158  * "In any profile that specifies bidirectional character handling, all
1159  * three of the following requirements MUST be met:
1160  *
1161  * 1) The characters in section 5.8 MUST be prohibited.
1162  *
1163  * 2) If a string contains any RandALCat character, the string MUST NOT
1164  * contain any LCat character.
1165  *
1166  * 3) If a string contains any RandALCat character, a RandALCat character
1167  * MUST be the first character of the string, and a RandALCat character
1168  * MUST be the last character of the string."
1169  */
1170  contains_RandALCat = false;
1171  for (i = 0; i < input_size; i++)
1172  {
1173  pg_wchar code = input_chars[i];
1174 
1176  {
1177  contains_RandALCat = true;
1178  break;
1179  }
1180  }
1181 
1182  if (contains_RandALCat)
1183  {
1184  pg_wchar first = input_chars[0];
1185  pg_wchar last = input_chars[input_size - 1];
1186 
1187  for (i = 0; i < input_size; i++)
1188  {
1189  pg_wchar code = input_chars[i];
1190 
1192  goto prohibited;
1193  }
1194 
1197  goto prohibited;
1198  }
1199 
1200  /*
1201  * Finally, convert the result back to UTF-8.
1202  */
1203  result_size = 0;
1204  for (wp = output_chars; *wp; wp++)
1205  {
1206  unsigned char buf[4];
1207 
1208  unicode_to_utf8(*wp, buf);
1209  result_size += pg_utf_mblen(buf);
1210  }
1211 
1212  result = ALLOC(result_size + 1);
1213  if (!result)
1214  goto oom;
1215 
1216  /*
1217  * There are no error exits below here, so the error exit paths don't need
1218  * to worry about possibly freeing "result".
1219  */
1220  p = (unsigned char *) result;
1221  for (wp = output_chars; *wp; wp++)
1222  {
1223  unicode_to_utf8(*wp, p);
1224  p += pg_utf_mblen(p);
1225  }
1226  Assert((char *) p == result + result_size);
1227  *p = '\0';
1228 
1229  FREE(input_chars);
1230  FREE(output_chars);
1231 
1232  *output = result;
1233  return SASLPREP_SUCCESS;
1234 
1235 prohibited:
1236  if (input_chars)
1237  FREE(input_chars);
1238  if (output_chars)
1239  FREE(output_chars);
1240 
1241  return SASLPREP_PROHIBITED;
1242 
1243 oom:
1244  if (input_chars)
1245  FREE(input_chars);
1246  if (output_chars)
1247  FREE(output_chars);
1248 
1249  return SASLPREP_OOM;
1250 }
#define Assert(condition)
Definition: c.h:863
#define MaxAllocSize
Definition: fe_memutils.h:22
FILE * input
FILE * output
int i
Definition: isn.c:72
static pg_wchar utf8_to_unicode(const unsigned char *c)
Definition: mbprint.c:53
unsigned int pg_wchar
Definition: mbprint.c:31
static char * buf
Definition: pg_test_fsync.c:72
#define pg_utf_mblen
Definition: pg_wchar.h:633
static unsigned char * unicode_to_utf8(pg_wchar c, unsigned char *utf8string)
Definition: pg_wchar.h:575
static const pg_wchar unassigned_codepoint_ranges[]
Definition: saslprep.c:158
static const pg_wchar non_ascii_space_ranges[]
Definition: saslprep.c:67
static const pg_wchar RandALCat_codepoint_ranges[]
Definition: saslprep.c:559
#define STRDUP(s)
Definition: saslprep.c:39
#define IS_CODE_IN_TABLE(code, map)
Definition: saslprep.c:966
#define ALLOC(size)
Definition: saslprep.c:40
#define FREE(size)
Definition: saslprep.c:41
static const pg_wchar LCat_codepoint_ranges[]
Definition: saslprep.c:598
static const pg_wchar commonly_mapped_to_nothing_ranges[]
Definition: saslprep.c:82
static const pg_wchar prohibited_output_ranges[]
Definition: saslprep.c:117
static int pg_utf8_string_len(const char *source)
Definition: saslprep.c:1003
bool pg_is_ascii(const char *str)
Definition: string.c:132
pg_wchar * unicode_normalize(UnicodeNormalizationForm form, const pg_wchar *input)
Definition: unicode_norm.c:402
@ UNICODE_NFKC
Definition: unicode_norm.h:23

References ALLOC, Assert, buf, commonly_mapped_to_nothing_ranges, FREE, i, input, IS_CODE_IN_TABLE, LCat_codepoint_ranges, MaxAllocSize, non_ascii_space_ranges, output, pg_is_ascii(), 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_NFKC, unicode_normalize(), unicode_to_utf8(), and utf8_to_unicode().

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