@@ -66,6 +66,7 @@ typedef struct check_network_data
66
66
} check_network_data ;
67
67
68
68
69
+ #define token_has_regexp (t ) (t->regex != NULL)
69
70
#define token_is_keyword (t , k ) (!t->quoted && strcmp(t->string, k) == 0)
70
71
#define token_matches (t , k ) (strcmp(t->string, k) == 0)
71
72
@@ -80,9 +81,10 @@ static MemoryContext parsed_hba_context = NULL;
80
81
* pre-parsed content of ident mapping file: list of IdentLine structs.
81
82
* parsed_ident_context is the memory context where it lives.
82
83
*
83
- * NOTE: the IdentLine structs can contain pre-compiled regular expressions
84
- * that live outside the memory context. Before destroying or resetting the
85
- * memory context, they need to be explicitly free'd.
84
+ * NOTE: the IdentLine structs can contain AuthTokens with pre-compiled
85
+ * regular expressions that live outside the memory context. Before
86
+ * destroying or resetting the memory context, they need to be explicitly
87
+ * free'd.
86
88
*/
87
89
static List * parsed_ident_lines = NIL ;
88
90
static MemoryContext parsed_ident_context = NULL ;
@@ -117,6 +119,9 @@ static List *tokenize_inc_file(List *tokens, const char *outer_filename,
117
119
const char * inc_filename , int elevel , char * * err_msg );
118
120
static bool parse_hba_auth_opt (char * name , char * val , HbaLine * hbaline ,
119
121
int elevel , char * * err_msg );
122
+ static int regcomp_auth_token (AuthToken * token );
123
+ static int regexec_auth_token (const char * match , AuthToken * token ,
124
+ size_t nmatch , regmatch_t pmatch []);
120
125
121
126
122
127
/*
@@ -267,14 +272,26 @@ make_auth_token(const char *token, bool quoted)
267
272
268
273
toklen = strlen (token );
269
274
/* we copy string into same palloc block as the struct */
270
- authtoken = (AuthToken * ) palloc (sizeof (AuthToken ) + toklen + 1 );
275
+ authtoken = (AuthToken * ) palloc0 (sizeof (AuthToken ) + toklen + 1 );
271
276
authtoken -> string = (char * ) authtoken + sizeof (AuthToken );
272
277
authtoken -> quoted = quoted ;
278
+ authtoken -> regex = NULL ;
273
279
memcpy (authtoken -> string , token , toklen + 1 );
274
280
275
281
return authtoken ;
276
282
}
277
283
284
+ /*
285
+ * Free an AuthToken, that may include a regular expression that needs
286
+ * to be cleaned up explicitly.
287
+ */
288
+ static void
289
+ free_auth_token (AuthToken * token )
290
+ {
291
+ if (token_has_regexp (token ))
292
+ pg_regfree (token -> regex );
293
+ }
294
+
278
295
/*
279
296
* Copy a AuthToken struct into freshly palloc'd memory.
280
297
*/
@@ -286,6 +303,56 @@ copy_auth_token(AuthToken *in)
286
303
return out ;
287
304
}
288
305
306
+ /*
307
+ * Compile the regular expression and store it in the AuthToken given in
308
+ * input. Returns the result of pg_regcomp().
309
+ */
310
+ static int
311
+ regcomp_auth_token (AuthToken * token )
312
+ {
313
+ pg_wchar * wstr ;
314
+ int wlen ;
315
+ int rc ;
316
+
317
+ Assert (token -> regex == NULL );
318
+
319
+ if (token -> string [0 ] != '/' )
320
+ return 0 ; /* nothing to compile */
321
+
322
+ token -> regex = (regex_t * ) palloc0 (sizeof (regex_t ));
323
+ wstr = palloc ((strlen (token -> string + 1 ) + 1 ) * sizeof (pg_wchar ));
324
+ wlen = pg_mb2wchar_with_len (token -> string + 1 ,
325
+ wstr , strlen (token -> string + 1 ));
326
+
327
+ rc = pg_regcomp (token -> regex , wstr , wlen , REG_ADVANCED , C_COLLATION_OID );
328
+
329
+ pfree (wstr );
330
+ return rc ;
331
+ }
332
+
333
+ /*
334
+ * Execute a regular expression computed in an AuthToken, checking for a match
335
+ * with the string specified in "match". The caller may optionally give an
336
+ * array to store the matches. Returns the result of pg_regexec().
337
+ */
338
+ static int
339
+ regexec_auth_token (const char * match , AuthToken * token , size_t nmatch ,
340
+ regmatch_t pmatch [])
341
+ {
342
+ pg_wchar * wmatchstr ;
343
+ int wmatchlen ;
344
+ int r ;
345
+
346
+ Assert (token -> string [0 ] == '/' && token -> regex );
347
+
348
+ wmatchstr = palloc ((strlen (match ) + 1 ) * sizeof (pg_wchar ));
349
+ wmatchlen = pg_mb2wchar_with_len (match , wmatchstr , strlen (match ));
350
+
351
+ r = pg_regexec (token -> regex , wmatchstr , wmatchlen , 0 , NULL , nmatch , pmatch , 0 );
352
+
353
+ pfree (wmatchstr );
354
+ return r ;
355
+ }
289
356
290
357
/*
291
358
* Tokenize one HBA field from a line, handling file inclusion and comma lists.
@@ -2307,6 +2374,7 @@ parse_ident_line(TokenizedAuthLine *tok_line, int elevel)
2307
2374
List * tokens ;
2308
2375
AuthToken * token ;
2309
2376
IdentLine * parsedline ;
2377
+ int rc ;
2310
2378
2311
2379
Assert (tok_line -> fields != NIL );
2312
2380
field = list_head (tok_line -> fields );
@@ -2326,7 +2394,9 @@ parse_ident_line(TokenizedAuthLine *tok_line, int elevel)
2326
2394
tokens = lfirst (field );
2327
2395
IDENT_MULTI_VALUE (tokens );
2328
2396
token = linitial (tokens );
2329
- parsedline -> ident_user = pstrdup (token -> string );
2397
+
2398
+ /* Copy the ident user token */
2399
+ parsedline -> token = copy_auth_token (token );
2330
2400
2331
2401
/* Get the PG rolename token */
2332
2402
field = lnext (tok_line -> fields , field );
@@ -2336,40 +2406,27 @@ parse_ident_line(TokenizedAuthLine *tok_line, int elevel)
2336
2406
token = linitial (tokens );
2337
2407
parsedline -> pg_role = pstrdup (token -> string );
2338
2408
2339
- if (parsedline -> ident_user [0 ] == '/' )
2409
+ /*
2410
+ * Now that the field validation is done, compile a regex from the user
2411
+ * token, if necessary.
2412
+ */
2413
+ rc = regcomp_auth_token (parsedline -> token );
2414
+ if (rc )
2340
2415
{
2341
- /*
2342
- * When system username starts with a slash, treat it as a regular
2343
- * expression. Pre-compile it.
2344
- */
2345
- int r ;
2346
- pg_wchar * wstr ;
2347
- int wlen ;
2348
-
2349
- wstr = palloc ((strlen (parsedline -> ident_user + 1 ) + 1 ) * sizeof (pg_wchar ));
2350
- wlen = pg_mb2wchar_with_len (parsedline -> ident_user + 1 ,
2351
- wstr , strlen (parsedline -> ident_user + 1 ));
2352
-
2353
- r = pg_regcomp (& parsedline -> re , wstr , wlen , REG_ADVANCED , C_COLLATION_OID );
2354
- if (r )
2355
- {
2356
- char errstr [100 ];
2416
+ char errstr [100 ];
2357
2417
2358
- pg_regerror (r , & parsedline -> re , errstr , sizeof (errstr ));
2359
- ereport (elevel ,
2360
- (errcode (ERRCODE_INVALID_REGULAR_EXPRESSION ),
2361
- errmsg ("invalid regular expression \"%s\": %s" ,
2362
- parsedline -> ident_user + 1 , errstr ),
2363
- errcontext ("line %d of configuration file \"%s\"" ,
2418
+ pg_regerror (rc , parsedline -> token -> regex , errstr , sizeof (errstr ));
2419
+ ereport (elevel ,
2420
+ (errcode (ERRCODE_INVALID_REGULAR_EXPRESSION ),
2421
+ errmsg ("invalid regular expression \"%s\": %s" ,
2422
+ parsedline -> token -> string + 1 , errstr ),
2423
+ errcontext ("line %d of configuration file \"%s\"" ,
2364
2424
line_num , IdentFileName )));
2365
2425
2366
- * err_msg = psprintf ("invalid regular expression \"%s\": %s" ,
2367
- parsedline -> ident_user + 1 , errstr );
2426
+ * err_msg = psprintf ("invalid regular expression \"%s\": %s" ,
2427
+ parsedline -> token -> string + 1 , errstr );
2368
2428
2369
- pfree (wstr );
2370
- return NULL ;
2371
- }
2372
- pfree (wstr );
2429
+ return NULL ;
2373
2430
}
2374
2431
2375
2432
return parsedline ;
@@ -2394,44 +2451,35 @@ check_ident_usermap(IdentLine *identLine, const char *usermap_name,
2394
2451
return ;
2395
2452
2396
2453
/* Match? */
2397
- if (identLine -> ident_user [ 0 ] == '/' )
2454
+ if (token_has_regexp ( identLine -> token ) )
2398
2455
{
2399
2456
/*
2400
- * When system username starts with a slash, treat it as a regular
2401
- * expression. In this case, we process the system username as a
2402
- * regular expression that returns exactly one match. This is replaced
2403
- * for \1 in the database username string, if present.
2457
+ * Process the system username as a regular expression that returns
2458
+ * exactly one match. This is replaced for \1 in the database username
2459
+ * string, if present.
2404
2460
*/
2405
2461
int r ;
2406
2462
regmatch_t matches [2 ];
2407
- pg_wchar * wstr ;
2408
- int wlen ;
2409
2463
char * ofs ;
2410
2464
char * regexp_pgrole ;
2411
2465
2412
- wstr = palloc ((strlen (ident_user ) + 1 ) * sizeof (pg_wchar ));
2413
- wlen = pg_mb2wchar_with_len (ident_user , wstr , strlen (ident_user ));
2414
-
2415
- r = pg_regexec (& identLine -> re , wstr , wlen , 0 , NULL , 2 , matches , 0 );
2466
+ r = regexec_auth_token (ident_user , identLine -> token , 2 , matches );
2416
2467
if (r )
2417
2468
{
2418
2469
char errstr [100 ];
2419
2470
2420
2471
if (r != REG_NOMATCH )
2421
2472
{
2422
2473
/* REG_NOMATCH is not an error, everything else is */
2423
- pg_regerror (r , & identLine -> re , errstr , sizeof (errstr ));
2474
+ pg_regerror (r , identLine -> token -> regex , errstr , sizeof (errstr ));
2424
2475
ereport (LOG ,
2425
2476
(errcode (ERRCODE_INVALID_REGULAR_EXPRESSION ),
2426
2477
errmsg ("regular expression match for \"%s\" failed: %s" ,
2427
- identLine -> ident_user + 1 , errstr )));
2478
+ identLine -> token -> string + 1 , errstr )));
2428
2479
* error_p = true;
2429
2480
}
2430
-
2431
- pfree (wstr );
2432
2481
return ;
2433
2482
}
2434
- pfree (wstr );
2435
2483
2436
2484
if ((ofs = strstr (identLine -> pg_role , "\\1" )) != NULL )
2437
2485
{
@@ -2443,7 +2491,7 @@ check_ident_usermap(IdentLine *identLine, const char *usermap_name,
2443
2491
ereport (LOG ,
2444
2492
(errcode (ERRCODE_INVALID_REGULAR_EXPRESSION ),
2445
2493
errmsg ("regular expression \"%s\" has no subexpressions as requested by backreference in \"%s\"" ,
2446
- identLine -> ident_user + 1 , identLine -> pg_role )));
2494
+ identLine -> token -> string + 1 , identLine -> pg_role )));
2447
2495
* error_p = true;
2448
2496
return ;
2449
2497
}
@@ -2490,13 +2538,13 @@ check_ident_usermap(IdentLine *identLine, const char *usermap_name,
2490
2538
if (case_insensitive )
2491
2539
{
2492
2540
if (pg_strcasecmp (identLine -> pg_role , pg_role ) == 0 &&
2493
- pg_strcasecmp (identLine -> ident_user , ident_user ) == 0 )
2541
+ pg_strcasecmp (identLine -> token -> string , ident_user ) == 0 )
2494
2542
* found_p = true;
2495
2543
}
2496
2544
else
2497
2545
{
2498
2546
if (strcmp (identLine -> pg_role , pg_role ) == 0 &&
2499
- strcmp (identLine -> ident_user , ident_user ) == 0 )
2547
+ strcmp (identLine -> token -> string , ident_user ) == 0 )
2500
2548
* found_p = true;
2501
2549
}
2502
2550
}
@@ -2646,8 +2694,7 @@ load_ident(void)
2646
2694
foreach (parsed_line_cell , new_parsed_lines )
2647
2695
{
2648
2696
newline = (IdentLine * ) lfirst (parsed_line_cell );
2649
- if (newline -> ident_user [0 ] == '/' )
2650
- pg_regfree (& newline -> re );
2697
+ free_auth_token (newline -> token );
2651
2698
}
2652
2699
MemoryContextDelete (ident_context );
2653
2700
return false;
@@ -2659,8 +2706,7 @@ load_ident(void)
2659
2706
foreach (parsed_line_cell , parsed_ident_lines )
2660
2707
{
2661
2708
newline = (IdentLine * ) lfirst (parsed_line_cell );
2662
- if (newline -> ident_user [0 ] == '/' )
2663
- pg_regfree (& newline -> re );
2709
+ free_auth_token (newline -> token );
2664
2710
}
2665
2711
}
2666
2712
if (parsed_ident_context != NULL )
0 commit comments