@@ -76,6 +76,13 @@ typedef struct
76
76
#define token_is_keyword (t , k ) (!t->quoted && strcmp(t->string, k) == 0)
77
77
#define token_matches (t , k ) (strcmp(t->string, k) == 0)
78
78
79
+ /*
80
+ * Memory context holding the list of TokenizedAuthLines when parsing
81
+ * HBA or ident configuration files. This is created when opening the first
82
+ * file (depth of 0).
83
+ */
84
+ static MemoryContext tokenize_context = NULL ;
85
+
79
86
/*
80
87
* pre-parsed content of HBA config file: list of HbaLine structs.
81
88
* parsed_hba_context is the memory context where it lives.
@@ -121,9 +128,9 @@ static const char *const UserAuthName[] =
121
128
};
122
129
123
130
124
- static List * tokenize_inc_file (List * tokens , const char * outer_filename ,
125
- const char * inc_filename , int elevel ,
126
- int depth , char * * err_msg );
131
+ static List * tokenize_expand_file (List * tokens , const char * outer_filename ,
132
+ const char * inc_filename , int elevel ,
133
+ int depth , char * * err_msg );
127
134
static bool parse_hba_auth_opt (char * name , char * val , HbaLine * hbaline ,
128
135
int elevel , char * * err_msg );
129
136
static int regcomp_auth_token (AuthToken * token , char * filename , int line_num ,
@@ -437,43 +444,53 @@ next_field_expand(const char *filename, char **lineptr,
437
444
438
445
/* Is this referencing a file? */
439
446
if (!initial_quote && buf [0 ] == '@' && buf [1 ] != '\0' )
440
- tokens = tokenize_inc_file (tokens , filename , buf + 1 ,
441
- elevel , depth + 1 , err_msg );
447
+ tokens = tokenize_expand_file (tokens , filename , buf + 1 ,
448
+ elevel , depth + 1 , err_msg );
442
449
else
450
+ {
451
+ MemoryContext oldcxt ;
452
+
453
+ /*
454
+ * lappend() may do its own allocations, so move to the context
455
+ * for the list of tokens.
456
+ */
457
+ oldcxt = MemoryContextSwitchTo (tokenize_context );
443
458
tokens = lappend (tokens , make_auth_token (buf , initial_quote ));
459
+ MemoryContextSwitchTo (oldcxt );
460
+ }
444
461
} while (trailing_comma && (* err_msg == NULL ));
445
462
446
463
return tokens ;
447
464
}
448
465
449
466
/*
450
- * tokenize_inc_file
467
+ * tokenize_expand_file
451
468
* Expand a file included from another file into an hba "field"
452
469
*
453
470
* Opens and tokenises a file included from another HBA config file with @,
454
471
* and returns all values found therein as a flat list of AuthTokens. If a
455
472
* @-token is found, recursively expand it. The newly read tokens are
456
473
* appended to "tokens" (so that foo,bar,@baz does what you expect).
457
- * All new tokens are allocated in caller's memory context.
474
+ * All new tokens are allocated in the memory context dedicated to the
475
+ * list of TokenizedAuthLines, aka tokenize_context.
458
476
*
459
477
* In event of an error, log a message at ereport level elevel, and also
460
478
* set *err_msg to a string describing the error. Note that the result
461
479
* may be non-NIL anyway, so *err_msg must be tested to determine whether
462
480
* there was an error.
463
481
*/
464
482
static List *
465
- tokenize_inc_file (List * tokens ,
466
- const char * outer_filename ,
467
- const char * inc_filename ,
468
- int elevel ,
469
- int depth ,
470
- char * * err_msg )
483
+ tokenize_expand_file (List * tokens ,
484
+ const char * outer_filename ,
485
+ const char * inc_filename ,
486
+ int elevel ,
487
+ int depth ,
488
+ char * * err_msg )
471
489
{
472
490
char * inc_fullname ;
473
491
FILE * inc_file ;
474
492
List * inc_lines ;
475
493
ListCell * inc_line ;
476
- MemoryContext linecxt ;
477
494
478
495
inc_fullname = AbsoluteConfigLocation (inc_filename , outer_filename );
479
496
inc_file = open_auth_file (inc_fullname , elevel , depth , err_msg );
@@ -486,13 +503,15 @@ tokenize_inc_file(List *tokens,
486
503
}
487
504
488
505
/* There is possible recursion here if the file contains @ */
489
- linecxt = tokenize_auth_file (inc_fullname , inc_file , & inc_lines , elevel ,
490
- depth );
506
+ tokenize_auth_file (inc_fullname , inc_file , & inc_lines , elevel ,
507
+ depth );
491
508
492
- FreeFile (inc_file );
493
509
pfree (inc_fullname );
494
510
495
- /* Copy all tokens found in the file and append to the tokens list */
511
+ /*
512
+ * Move all the tokens found in the file to the tokens list. These are
513
+ * already saved in tokenize_context.
514
+ */
496
515
foreach (inc_line , inc_lines )
497
516
{
498
517
TokenizedAuthLine * tok_line = (TokenizedAuthLine * ) lfirst (inc_line );
@@ -513,16 +532,40 @@ tokenize_inc_file(List *tokens,
513
532
foreach (inc_token , inc_tokens )
514
533
{
515
534
AuthToken * token = lfirst (inc_token );
535
+ MemoryContext oldcxt ;
516
536
517
- tokens = lappend (tokens , copy_auth_token (token ));
537
+ /*
538
+ * lappend() may do its own allocations, so move to the
539
+ * context for the list of tokens.
540
+ */
541
+ oldcxt = MemoryContextSwitchTo (tokenize_context );
542
+ tokens = lappend (tokens , token );
543
+ MemoryContextSwitchTo (oldcxt );
518
544
}
519
545
}
520
546
}
521
547
522
- MemoryContextDelete ( linecxt );
548
+ free_auth_file ( inc_file , depth );
523
549
return tokens ;
524
550
}
525
551
552
+ /*
553
+ * free_auth_file
554
+ * Free a file opened by open_auth_file().
555
+ */
556
+ void
557
+ free_auth_file (FILE * file , int depth )
558
+ {
559
+ FreeFile (file );
560
+
561
+ /* If this is the last cleanup, remove the tokenization context */
562
+ if (depth == 0 )
563
+ {
564
+ MemoryContextDelete (tokenize_context );
565
+ tokenize_context = NULL ;
566
+ }
567
+ }
568
+
526
569
/*
527
570
* open_auth_file
528
571
* Open the given file.
@@ -558,6 +601,22 @@ open_auth_file(const char *filename, int elevel, int depth,
558
601
return NULL ;
559
602
}
560
603
604
+ /*
605
+ * When opening the top-level file, create the memory context used for the
606
+ * tokenization. This will be closed with this file when coming back to
607
+ * this level of cleanup.
608
+ */
609
+ if (depth == 0 )
610
+ {
611
+ /*
612
+ * A context may be present, but assume that it has been eliminated
613
+ * already.
614
+ */
615
+ tokenize_context = AllocSetContextCreate (CurrentMemoryContext ,
616
+ "tokenize_context" ,
617
+ ALLOCSET_START_SMALL_SIZES );
618
+ }
619
+
561
620
file = AllocateFile (filename , "r" );
562
621
if (file == NULL )
563
622
{
@@ -570,6 +629,8 @@ open_auth_file(const char *filename, int elevel, int depth,
570
629
if (err_msg )
571
630
* err_msg = psprintf ("could not open file \"%s\": %s" ,
572
631
filename , strerror (save_errno ));
632
+ /* the caller may care about some specific errno */
633
+ errno = save_errno ;
573
634
return NULL ;
574
635
}
575
636
@@ -593,32 +654,34 @@ tokenize_error_callback(void *arg)
593
654
* Tokenize the given file.
594
655
*
595
656
* The output is a list of TokenizedAuthLine structs; see the struct definition
596
- * in libpq/hba.h.
657
+ * in libpq/hba.h. This is the central piece in charge of parsing the
658
+ * authentication files. All the operations of this function happen in its own
659
+ * local memory context, easing the cleanup of anything allocated here. This
660
+ * matters a lot when reloading authentication files in the postmaster.
597
661
*
598
662
* filename: the absolute path to the target file
599
663
* file: the already-opened target file
600
- * tok_lines: receives output list
664
+ * tok_lines: receives output list, saved into tokenize_context
601
665
* elevel: message logging level
602
666
* depth: level of recursion when tokenizing the target file
603
667
*
604
668
* Errors are reported by logging messages at ereport level elevel and by
605
669
* adding TokenizedAuthLine structs containing non-null err_msg fields to the
606
670
* output list.
607
- *
608
- * Return value is a memory context which contains all memory allocated by
609
- * this function (it's a child of caller's context).
610
671
*/
611
- MemoryContext
672
+ void
612
673
tokenize_auth_file (const char * filename , FILE * file , List * * tok_lines ,
613
674
int elevel , int depth )
614
675
{
615
676
int line_number = 1 ;
616
677
StringInfoData buf ;
617
678
MemoryContext linecxt ;
618
- MemoryContext oldcxt ;
679
+ MemoryContext funccxt ; /* context of this function's caller */
619
680
ErrorContextCallback tokenerrcontext ;
620
681
tokenize_error_callback_arg callback_arg ;
621
682
683
+ Assert (tokenize_context );
684
+
622
685
callback_arg .filename = filename ;
623
686
callback_arg .linenum = line_number ;
624
687
@@ -627,14 +690,19 @@ tokenize_auth_file(const char *filename, FILE *file, List **tok_lines,
627
690
tokenerrcontext .previous = error_context_stack ;
628
691
error_context_stack = & tokenerrcontext ;
629
692
693
+ /*
694
+ * Do all the local tokenization in its own context, to ease the cleanup
695
+ * of any memory allocated while tokenizing.
696
+ */
630
697
linecxt = AllocSetContextCreate (CurrentMemoryContext ,
631
698
"tokenize_auth_file" ,
632
699
ALLOCSET_SMALL_SIZES );
633
- oldcxt = MemoryContextSwitchTo (linecxt );
700
+ funccxt = MemoryContextSwitchTo (linecxt );
634
701
635
702
initStringInfo (& buf );
636
703
637
- * tok_lines = NIL ;
704
+ if (depth == 0 )
705
+ * tok_lines = NIL ;
638
706
639
707
while (!feof (file ) && !ferror (file ))
640
708
{
@@ -694,7 +762,17 @@ tokenize_auth_file(const char *filename, FILE *file, List **tok_lines,
694
762
elevel , depth , & err_msg );
695
763
/* add field to line, unless we are at EOL or comment start */
696
764
if (current_field != NIL )
765
+ {
766
+ MemoryContext oldcxt ;
767
+
768
+ /*
769
+ * lappend() may do its own allocations, so move to the
770
+ * context for the list of tokens.
771
+ */
772
+ oldcxt = MemoryContextSwitchTo (tokenize_context );
697
773
current_line = lappend (current_line , current_field );
774
+ MemoryContextSwitchTo (oldcxt );
775
+ }
698
776
}
699
777
700
778
/*
@@ -703,25 +781,27 @@ tokenize_auth_file(const char *filename, FILE *file, List **tok_lines,
703
781
if (current_line != NIL || err_msg != NULL )
704
782
{
705
783
TokenizedAuthLine * tok_line ;
784
+ MemoryContext oldcxt ;
706
785
786
+ oldcxt = MemoryContextSwitchTo (tokenize_context );
707
787
tok_line = (TokenizedAuthLine * ) palloc (sizeof (TokenizedAuthLine ));
708
788
tok_line -> fields = current_line ;
709
789
tok_line -> file_name = pstrdup (filename );
710
790
tok_line -> line_num = line_number ;
711
791
tok_line -> raw_line = pstrdup (buf .data );
712
- tok_line -> err_msg = err_msg ;
792
+ tok_line -> err_msg = err_msg ? pstrdup ( err_msg ) : NULL ;
713
793
* tok_lines = lappend (* tok_lines , tok_line );
794
+ MemoryContextSwitchTo (oldcxt );
714
795
}
715
796
716
797
line_number += continuations + 1 ;
717
798
callback_arg .linenum = line_number ;
718
799
}
719
800
720
- MemoryContextSwitchTo (oldcxt );
801
+ MemoryContextSwitchTo (funccxt );
802
+ MemoryContextDelete (linecxt );
721
803
722
804
error_context_stack = tokenerrcontext .previous ;
723
-
724
- return linecxt ;
725
805
}
726
806
727
807
@@ -2409,7 +2489,6 @@ load_hba(void)
2409
2489
ListCell * line ;
2410
2490
List * new_parsed_lines = NIL ;
2411
2491
bool ok = true;
2412
- MemoryContext linecxt ;
2413
2492
MemoryContext oldcxt ;
2414
2493
MemoryContext hbacxt ;
2415
2494
@@ -2420,8 +2499,7 @@ load_hba(void)
2420
2499
return false;
2421
2500
}
2422
2501
2423
- linecxt = tokenize_auth_file (HbaFileName , file , & hba_lines , LOG , 0 );
2424
- FreeFile (file );
2502
+ tokenize_auth_file (HbaFileName , file , & hba_lines , LOG , 0 );
2425
2503
2426
2504
/* Now parse all the lines */
2427
2505
Assert (PostmasterContext );
@@ -2472,7 +2550,7 @@ load_hba(void)
2472
2550
}
2473
2551
2474
2552
/* Free tokenizer memory */
2475
- MemoryContextDelete ( linecxt );
2553
+ free_auth_file ( file , 0 );
2476
2554
MemoryContextSwitchTo (oldcxt );
2477
2555
2478
2556
if (!ok )
@@ -2776,7 +2854,6 @@ load_ident(void)
2776
2854
* parsed_line_cell ;
2777
2855
List * new_parsed_lines = NIL ;
2778
2856
bool ok = true;
2779
- MemoryContext linecxt ;
2780
2857
MemoryContext oldcxt ;
2781
2858
MemoryContext ident_context ;
2782
2859
IdentLine * newline ;
@@ -2789,8 +2866,7 @@ load_ident(void)
2789
2866
return false;
2790
2867
}
2791
2868
2792
- linecxt = tokenize_auth_file (IdentFileName , file , & ident_lines , LOG , 0 );
2793
- FreeFile (file );
2869
+ tokenize_auth_file (IdentFileName , file , & ident_lines , LOG , 0 );
2794
2870
2795
2871
/* Now parse all the lines */
2796
2872
Assert (PostmasterContext );
@@ -2826,7 +2902,7 @@ load_ident(void)
2826
2902
}
2827
2903
2828
2904
/* Free tokenizer memory */
2829
- MemoryContextDelete ( linecxt );
2905
+ free_auth_file ( file , 0 );
2830
2906
MemoryContextSwitchTo (oldcxt );
2831
2907
2832
2908
if (!ok )
0 commit comments