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{
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
1235prohibited:
1236 if (input_chars)
1237 FREE(input_chars);
1238 if (output_chars)
1239 FREE(output_chars);
1240
1241 return SASLPREP_PROHIBITED;
1242
1243oom:
1244 if (input_chars)
1245 FREE(input_chars);
1246 if (output_chars)
1247 FREE(output_chars);
1248
1249 return SASLPREP_OOM;
1250}
#define MaxAllocSize
Definition: fe_memutils.h:22
Assert(PointerIsAligned(start, uint64))
FILE * input
FILE * output
int i
Definition: isn.c:77
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().