LCOV - code coverage report
Current view: top level - src/backend/utils/adt - hbafuncs.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 136 229 59.4 %
Date: 2025-01-18 04:15:08 Functions: 7 7 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * hbafuncs.c
       4             :  *    Support functions for SQL views of authentication files.
       5             :  *
       6             :  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/utils/adt/hbafuncs.c
      12             :  *
      13             :  *-------------------------------------------------------------------------
      14             :  */
      15             : #include "postgres.h"
      16             : 
      17             : #include "catalog/objectaddress.h"
      18             : #include "common/ip.h"
      19             : #include "funcapi.h"
      20             : #include "libpq/hba.h"
      21             : #include "utils/array.h"
      22             : #include "utils/builtins.h"
      23             : #include "utils/guc.h"
      24             : 
      25             : 
      26             : static ArrayType *get_hba_options(HbaLine *hba);
      27             : static void fill_hba_line(Tuplestorestate *tuple_store, TupleDesc tupdesc,
      28             :                           int rule_number, char *filename, int lineno,
      29             :                           HbaLine *hba, const char *err_msg);
      30             : static void fill_hba_view(Tuplestorestate *tuple_store, TupleDesc tupdesc);
      31             : static void fill_ident_line(Tuplestorestate *tuple_store, TupleDesc tupdesc,
      32             :                             int map_number, char *filename, int lineno,
      33             :                             IdentLine *ident, const char *err_msg);
      34             : static void fill_ident_view(Tuplestorestate *tuple_store, TupleDesc tupdesc);
      35             : 
      36             : 
      37             : /*
      38             :  * This macro specifies the maximum number of authentication options
      39             :  * that are possible with any given authentication method that is supported.
      40             :  * Currently LDAP supports 12, and there are 3 that are not dependent on
      41             :  * the auth method here.  It may not actually be possible to set all of them
      42             :  * at the same time, but we'll set the macro value high enough to be
      43             :  * conservative and avoid warnings from static analysis tools.
      44             :  */
      45             : #define MAX_HBA_OPTIONS 15
      46             : 
      47             : /*
      48             :  * Create a text array listing the options specified in the HBA line.
      49             :  * Return NULL if no options are specified.
      50             :  */
      51             : static ArrayType *
      52          56 : get_hba_options(HbaLine *hba)
      53             : {
      54             :     int         noptions;
      55             :     Datum       options[MAX_HBA_OPTIONS];
      56             : 
      57          56 :     noptions = 0;
      58             : 
      59          56 :     if (hba->auth_method == uaGSS || hba->auth_method == uaSSPI)
      60             :     {
      61           0 :         if (hba->include_realm)
      62           0 :             options[noptions++] =
      63           0 :                 CStringGetTextDatum("include_realm=true");
      64             : 
      65           0 :         if (hba->krb_realm)
      66           0 :             options[noptions++] =
      67           0 :                 CStringGetTextDatum(psprintf("krb_realm=%s", hba->krb_realm));
      68             :     }
      69             : 
      70          56 :     if (hba->usermap)
      71           0 :         options[noptions++] =
      72           0 :             CStringGetTextDatum(psprintf("map=%s", hba->usermap));
      73             : 
      74          56 :     if (hba->clientcert != clientCertOff)
      75           0 :         options[noptions++] =
      76           0 :             CStringGetTextDatum(psprintf("clientcert=%s", (hba->clientcert == clientCertCA) ? "verify-ca" : "verify-full"));
      77             : 
      78          56 :     if (hba->pamservice)
      79           0 :         options[noptions++] =
      80           0 :             CStringGetTextDatum(psprintf("pamservice=%s", hba->pamservice));
      81             : 
      82          56 :     if (hba->auth_method == uaLDAP)
      83             :     {
      84           0 :         if (hba->ldapserver)
      85           0 :             options[noptions++] =
      86           0 :                 CStringGetTextDatum(psprintf("ldapserver=%s", hba->ldapserver));
      87             : 
      88           0 :         if (hba->ldapport)
      89           0 :             options[noptions++] =
      90           0 :                 CStringGetTextDatum(psprintf("ldapport=%d", hba->ldapport));
      91             : 
      92           0 :         if (hba->ldapscheme)
      93           0 :             options[noptions++] =
      94           0 :                 CStringGetTextDatum(psprintf("ldapscheme=%s", hba->ldapscheme));
      95             : 
      96           0 :         if (hba->ldaptls)
      97           0 :             options[noptions++] =
      98           0 :                 CStringGetTextDatum("ldaptls=true");
      99             : 
     100           0 :         if (hba->ldapprefix)
     101           0 :             options[noptions++] =
     102           0 :                 CStringGetTextDatum(psprintf("ldapprefix=%s", hba->ldapprefix));
     103             : 
     104           0 :         if (hba->ldapsuffix)
     105           0 :             options[noptions++] =
     106           0 :                 CStringGetTextDatum(psprintf("ldapsuffix=%s", hba->ldapsuffix));
     107             : 
     108           0 :         if (hba->ldapbasedn)
     109           0 :             options[noptions++] =
     110           0 :                 CStringGetTextDatum(psprintf("ldapbasedn=%s", hba->ldapbasedn));
     111             : 
     112           0 :         if (hba->ldapbinddn)
     113           0 :             options[noptions++] =
     114           0 :                 CStringGetTextDatum(psprintf("ldapbinddn=%s", hba->ldapbinddn));
     115             : 
     116           0 :         if (hba->ldapbindpasswd)
     117           0 :             options[noptions++] =
     118           0 :                 CStringGetTextDatum(psprintf("ldapbindpasswd=%s",
     119             :                                              hba->ldapbindpasswd));
     120             : 
     121           0 :         if (hba->ldapsearchattribute)
     122           0 :             options[noptions++] =
     123           0 :                 CStringGetTextDatum(psprintf("ldapsearchattribute=%s",
     124             :                                              hba->ldapsearchattribute));
     125             : 
     126           0 :         if (hba->ldapsearchfilter)
     127           0 :             options[noptions++] =
     128           0 :                 CStringGetTextDatum(psprintf("ldapsearchfilter=%s",
     129             :                                              hba->ldapsearchfilter));
     130             : 
     131           0 :         if (hba->ldapscope)
     132           0 :             options[noptions++] =
     133           0 :                 CStringGetTextDatum(psprintf("ldapscope=%d", hba->ldapscope));
     134             :     }
     135             : 
     136          56 :     if (hba->auth_method == uaRADIUS)
     137             :     {
     138           0 :         if (hba->radiusservers_s)
     139           0 :             options[noptions++] =
     140           0 :                 CStringGetTextDatum(psprintf("radiusservers=%s", hba->radiusservers_s));
     141             : 
     142           0 :         if (hba->radiussecrets_s)
     143           0 :             options[noptions++] =
     144           0 :                 CStringGetTextDatum(psprintf("radiussecrets=%s", hba->radiussecrets_s));
     145             : 
     146           0 :         if (hba->radiusidentifiers_s)
     147           0 :             options[noptions++] =
     148           0 :                 CStringGetTextDatum(psprintf("radiusidentifiers=%s", hba->radiusidentifiers_s));
     149             : 
     150           0 :         if (hba->radiusports_s)
     151           0 :             options[noptions++] =
     152           0 :                 CStringGetTextDatum(psprintf("radiusports=%s", hba->radiusports_s));
     153             :     }
     154             : 
     155             :     /* If you add more options, consider increasing MAX_HBA_OPTIONS. */
     156             :     Assert(noptions <= MAX_HBA_OPTIONS);
     157             : 
     158          56 :     if (noptions > 0)
     159           0 :         return construct_array_builtin(options, noptions, TEXTOID);
     160             :     else
     161          56 :         return NULL;
     162             : }
     163             : 
     164             : /* Number of columns in pg_hba_file_rules view */
     165             : #define NUM_PG_HBA_FILE_RULES_ATTS   11
     166             : 
     167             : /*
     168             :  * fill_hba_line
     169             :  *      Build one row of pg_hba_file_rules view, add it to tuplestore.
     170             :  *
     171             :  * tuple_store: where to store data
     172             :  * tupdesc: tuple descriptor for the view
     173             :  * rule_number: unique identifier among all valid rules
     174             :  * filename: configuration file name (must always be valid)
     175             :  * lineno: line number of configuration file (must always be valid)
     176             :  * hba: parsed line data (can be NULL, in which case err_msg should be set)
     177             :  * err_msg: error message (NULL if none)
     178             :  *
     179             :  * Note: leaks memory, but we don't care since this is run in a short-lived
     180             :  * memory context.
     181             :  */
     182             : static void
     183          56 : fill_hba_line(Tuplestorestate *tuple_store, TupleDesc tupdesc,
     184             :               int rule_number, char *filename, int lineno, HbaLine *hba,
     185             :               const char *err_msg)
     186             : {
     187             :     Datum       values[NUM_PG_HBA_FILE_RULES_ATTS];
     188             :     bool        nulls[NUM_PG_HBA_FILE_RULES_ATTS];
     189             :     char        buffer[NI_MAXHOST];
     190             :     HeapTuple   tuple;
     191             :     int         index;
     192             :     ListCell   *lc;
     193             :     const char *typestr;
     194             :     const char *addrstr;
     195             :     const char *maskstr;
     196             :     ArrayType  *options;
     197             : 
     198             :     Assert(tupdesc->natts == NUM_PG_HBA_FILE_RULES_ATTS);
     199             : 
     200          56 :     memset(values, 0, sizeof(values));
     201          56 :     memset(nulls, 0, sizeof(nulls));
     202          56 :     index = 0;
     203             : 
     204             :     /* rule_number, nothing on error */
     205          56 :     if (err_msg)
     206           0 :         nulls[index++] = true;
     207             :     else
     208          56 :         values[index++] = Int32GetDatum(rule_number);
     209             : 
     210             :     /* file_name */
     211          56 :     values[index++] = CStringGetTextDatum(filename);
     212             : 
     213             :     /* line_number */
     214          56 :     values[index++] = Int32GetDatum(lineno);
     215             : 
     216          56 :     if (hba != NULL)
     217             :     {
     218             :         /* type */
     219             :         /* Avoid a default: case so compiler will warn about missing cases */
     220          56 :         typestr = NULL;
     221          56 :         switch (hba->conntype)
     222             :         {
     223          32 :             case ctLocal:
     224          32 :                 typestr = "local";
     225          32 :                 break;
     226          24 :             case ctHost:
     227          24 :                 typestr = "host";
     228          24 :                 break;
     229           0 :             case ctHostSSL:
     230           0 :                 typestr = "hostssl";
     231           0 :                 break;
     232           0 :             case ctHostNoSSL:
     233           0 :                 typestr = "hostnossl";
     234           0 :                 break;
     235           0 :             case ctHostGSS:
     236           0 :                 typestr = "hostgssenc";
     237           0 :                 break;
     238           0 :             case ctHostNoGSS:
     239           0 :                 typestr = "hostnogssenc";
     240           0 :                 break;
     241             :         }
     242          56 :         if (typestr)
     243          56 :             values[index++] = CStringGetTextDatum(typestr);
     244             :         else
     245           0 :             nulls[index++] = true;
     246             : 
     247             :         /* database */
     248          56 :         if (hba->databases)
     249             :         {
     250             :             /*
     251             :              * Flatten AuthToken list to string list.  It might seem that we
     252             :              * should re-quote any quoted tokens, but that has been rejected
     253             :              * on the grounds that it makes it harder to compare the array
     254             :              * elements to other system catalogs.  That makes entries like
     255             :              * "all" or "samerole" formally ambiguous ... but users who name
     256             :              * databases/roles that way are inflicting their own pain.
     257             :              */
     258          56 :             List       *names = NIL;
     259             : 
     260         114 :             foreach(lc, hba->databases)
     261             :             {
     262          58 :                 AuthToken  *tok = lfirst(lc);
     263             : 
     264          58 :                 names = lappend(names, tok->string);
     265             :             }
     266          56 :             values[index++] = PointerGetDatum(strlist_to_textarray(names));
     267             :         }
     268             :         else
     269           0 :             nulls[index++] = true;
     270             : 
     271             :         /* user */
     272          56 :         if (hba->roles)
     273             :         {
     274             :             /* Flatten AuthToken list to string list; see comment above */
     275          56 :             List       *roles = NIL;
     276             : 
     277         112 :             foreach(lc, hba->roles)
     278             :             {
     279          56 :                 AuthToken  *tok = lfirst(lc);
     280             : 
     281          56 :                 roles = lappend(roles, tok->string);
     282             :             }
     283          56 :             values[index++] = PointerGetDatum(strlist_to_textarray(roles));
     284             :         }
     285             :         else
     286           0 :             nulls[index++] = true;
     287             : 
     288             :         /* address and netmask */
     289             :         /* Avoid a default: case so compiler will warn about missing cases */
     290          56 :         addrstr = maskstr = NULL;
     291          56 :         switch (hba->ip_cmp_method)
     292             :         {
     293          56 :             case ipCmpMask:
     294          56 :                 if (hba->hostname)
     295             :                 {
     296           0 :                     addrstr = hba->hostname;
     297             :                 }
     298             :                 else
     299             :                 {
     300             :                     /*
     301             :                      * Note: if pg_getnameinfo_all fails, it'll set buffer to
     302             :                      * "???", which we want to return.
     303             :                      */
     304          56 :                     if (hba->addrlen > 0)
     305             :                     {
     306          24 :                         if (pg_getnameinfo_all(&hba->addr, hba->addrlen,
     307             :                                                buffer, sizeof(buffer),
     308             :                                                NULL, 0,
     309             :                                                NI_NUMERICHOST) == 0)
     310          24 :                             clean_ipv6_addr(hba->addr.ss_family, buffer);
     311          24 :                         addrstr = pstrdup(buffer);
     312             :                     }
     313          56 :                     if (hba->masklen > 0)
     314             :                     {
     315          24 :                         if (pg_getnameinfo_all(&hba->mask, hba->masklen,
     316             :                                                buffer, sizeof(buffer),
     317             :                                                NULL, 0,
     318             :                                                NI_NUMERICHOST) == 0)
     319          24 :                             clean_ipv6_addr(hba->mask.ss_family, buffer);
     320          24 :                         maskstr = pstrdup(buffer);
     321             :                     }
     322             :                 }
     323          56 :                 break;
     324           0 :             case ipCmpAll:
     325           0 :                 addrstr = "all";
     326           0 :                 break;
     327           0 :             case ipCmpSameHost:
     328           0 :                 addrstr = "samehost";
     329           0 :                 break;
     330           0 :             case ipCmpSameNet:
     331           0 :                 addrstr = "samenet";
     332           0 :                 break;
     333             :         }
     334          56 :         if (addrstr)
     335          24 :             values[index++] = CStringGetTextDatum(addrstr);
     336             :         else
     337          32 :             nulls[index++] = true;
     338          56 :         if (maskstr)
     339          24 :             values[index++] = CStringGetTextDatum(maskstr);
     340             :         else
     341          32 :             nulls[index++] = true;
     342             : 
     343             :         /* auth_method */
     344          56 :         values[index++] = CStringGetTextDatum(hba_authname(hba->auth_method));
     345             : 
     346             :         /* options */
     347          56 :         options = get_hba_options(hba);
     348          56 :         if (options)
     349           0 :             values[index++] = PointerGetDatum(options);
     350             :         else
     351          56 :             nulls[index++] = true;
     352             :     }
     353             :     else
     354             :     {
     355             :         /* no parsing result, so set relevant fields to nulls */
     356           0 :         memset(&nulls[3], true, (NUM_PG_HBA_FILE_RULES_ATTS - 4) * sizeof(bool));
     357             :     }
     358             : 
     359             :     /* error */
     360          56 :     if (err_msg)
     361           0 :         values[NUM_PG_HBA_FILE_RULES_ATTS - 1] = CStringGetTextDatum(err_msg);
     362             :     else
     363          56 :         nulls[NUM_PG_HBA_FILE_RULES_ATTS - 1] = true;
     364             : 
     365          56 :     tuple = heap_form_tuple(tupdesc, values, nulls);
     366          56 :     tuplestore_puttuple(tuple_store, tuple);
     367          56 : }
     368             : 
     369             : /*
     370             :  * fill_hba_view
     371             :  *      Read the pg_hba.conf file and fill the tuplestore with view records.
     372             :  */
     373             : static void
     374           8 : fill_hba_view(Tuplestorestate *tuple_store, TupleDesc tupdesc)
     375             : {
     376             :     FILE       *file;
     377           8 :     List       *hba_lines = NIL;
     378             :     ListCell   *line;
     379           8 :     int         rule_number = 0;
     380             :     MemoryContext hbacxt;
     381             :     MemoryContext oldcxt;
     382             : 
     383             :     /*
     384             :      * In the unlikely event that we can't open pg_hba.conf, we throw an
     385             :      * error, rather than trying to report it via some sort of view entry.
     386             :      * (Most other error conditions should result in a message in a view
     387             :      * entry.)
     388             :      */
     389           8 :     file = open_auth_file(HbaFileName, ERROR, 0, NULL);
     390             : 
     391           8 :     tokenize_auth_file(HbaFileName, file, &hba_lines, DEBUG3, 0);
     392             : 
     393             :     /* Now parse all the lines */
     394           8 :     hbacxt = AllocSetContextCreate(CurrentMemoryContext,
     395             :                                    "hba parser context",
     396             :                                    ALLOCSET_SMALL_SIZES);
     397           8 :     oldcxt = MemoryContextSwitchTo(hbacxt);
     398          64 :     foreach(line, hba_lines)
     399             :     {
     400          56 :         TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line);
     401          56 :         HbaLine    *hbaline = NULL;
     402             : 
     403             :         /* don't parse lines that already have errors */
     404          56 :         if (tok_line->err_msg == NULL)
     405          56 :             hbaline = parse_hba_line(tok_line, DEBUG3);
     406             : 
     407             :         /* No error, set a new rule number */
     408          56 :         if (tok_line->err_msg == NULL)
     409          56 :             rule_number++;
     410             : 
     411          56 :         fill_hba_line(tuple_store, tupdesc, rule_number,
     412             :                       tok_line->file_name, tok_line->line_num, hbaline,
     413          56 :                       tok_line->err_msg);
     414             :     }
     415             : 
     416             :     /* Free tokenizer memory */
     417           8 :     free_auth_file(file, 0);
     418             :     /* Free parse_hba_line memory */
     419           8 :     MemoryContextSwitchTo(oldcxt);
     420           8 :     MemoryContextDelete(hbacxt);
     421           8 : }
     422             : 
     423             : /*
     424             :  * pg_hba_file_rules
     425             :  *
     426             :  * SQL-accessible set-returning function to return all the entries in the
     427             :  * pg_hba.conf file.
     428             :  */
     429             : Datum
     430           8 : pg_hba_file_rules(PG_FUNCTION_ARGS)
     431             : {
     432             :     ReturnSetInfo *rsi;
     433             : 
     434             :     /*
     435             :      * Build tuplestore to hold the result rows.  We must use the Materialize
     436             :      * mode to be safe against HBA file changes while the cursor is open. It's
     437             :      * also more efficient than having to look up our current position in the
     438             :      * parsed list every time.
     439             :      */
     440           8 :     InitMaterializedSRF(fcinfo, 0);
     441             : 
     442             :     /* Fill the tuplestore */
     443           8 :     rsi = (ReturnSetInfo *) fcinfo->resultinfo;
     444           8 :     fill_hba_view(rsi->setResult, rsi->setDesc);
     445             : 
     446           8 :     PG_RETURN_NULL();
     447             : }
     448             : 
     449             : /* Number of columns in pg_ident_file_mappings view */
     450             : #define NUM_PG_IDENT_FILE_MAPPINGS_ATTS  7
     451             : 
     452             : /*
     453             :  * fill_ident_line: build one row of pg_ident_file_mappings view, add it to
     454             :  * tuplestore
     455             :  *
     456             :  * tuple_store: where to store data
     457             :  * tupdesc: tuple descriptor for the view
     458             :  * map_number: unique identifier among all valid maps
     459             :  * filename: configuration file name (must always be valid)
     460             :  * lineno: line number of configuration file (must always be valid)
     461             :  * ident: parsed line data (can be NULL, in which case err_msg should be set)
     462             :  * err_msg: error message (NULL if none)
     463             :  *
     464             :  * Note: leaks memory, but we don't care since this is run in a short-lived
     465             :  * memory context.
     466             :  */
     467             : static void
     468          16 : fill_ident_line(Tuplestorestate *tuple_store, TupleDesc tupdesc,
     469             :                 int map_number, char *filename, int lineno, IdentLine *ident,
     470             :                 const char *err_msg)
     471             : {
     472             :     Datum       values[NUM_PG_IDENT_FILE_MAPPINGS_ATTS];
     473             :     bool        nulls[NUM_PG_IDENT_FILE_MAPPINGS_ATTS];
     474             :     HeapTuple   tuple;
     475             :     int         index;
     476             : 
     477             :     Assert(tupdesc->natts == NUM_PG_IDENT_FILE_MAPPINGS_ATTS);
     478             : 
     479          16 :     memset(values, 0, sizeof(values));
     480          16 :     memset(nulls, 0, sizeof(nulls));
     481          16 :     index = 0;
     482             : 
     483             :     /* map_number, nothing on error */
     484          16 :     if (err_msg)
     485           0 :         nulls[index++] = true;
     486             :     else
     487          16 :         values[index++] = Int32GetDatum(map_number);
     488             : 
     489             :     /* file_name */
     490          16 :     values[index++] = CStringGetTextDatum(filename);
     491             : 
     492             :     /* line_number */
     493          16 :     values[index++] = Int32GetDatum(lineno);
     494             : 
     495          16 :     if (ident != NULL)
     496             :     {
     497          16 :         values[index++] = CStringGetTextDatum(ident->usermap);
     498          16 :         values[index++] = CStringGetTextDatum(ident->system_user->string);
     499          16 :         values[index++] = CStringGetTextDatum(ident->pg_user->string);
     500             :     }
     501             :     else
     502             :     {
     503             :         /* no parsing result, so set relevant fields to nulls */
     504           0 :         memset(&nulls[3], true, (NUM_PG_IDENT_FILE_MAPPINGS_ATTS - 4) * sizeof(bool));
     505             :     }
     506             : 
     507             :     /* error */
     508          16 :     if (err_msg)
     509           0 :         values[NUM_PG_IDENT_FILE_MAPPINGS_ATTS - 1] = CStringGetTextDatum(err_msg);
     510             :     else
     511          16 :         nulls[NUM_PG_IDENT_FILE_MAPPINGS_ATTS - 1] = true;
     512             : 
     513          16 :     tuple = heap_form_tuple(tupdesc, values, nulls);
     514          16 :     tuplestore_puttuple(tuple_store, tuple);
     515          16 : }
     516             : 
     517             : /*
     518             :  * Read the pg_ident.conf file and fill the tuplestore with view records.
     519             :  */
     520             : static void
     521           8 : fill_ident_view(Tuplestorestate *tuple_store, TupleDesc tupdesc)
     522             : {
     523             :     FILE       *file;
     524           8 :     List       *ident_lines = NIL;
     525             :     ListCell   *line;
     526           8 :     int         map_number = 0;
     527             :     MemoryContext identcxt;
     528             :     MemoryContext oldcxt;
     529             : 
     530             :     /*
     531             :      * In the unlikely event that we can't open pg_ident.conf, we throw an
     532             :      * error, rather than trying to report it via some sort of view entry.
     533             :      * (Most other error conditions should result in a message in a view
     534             :      * entry.)
     535             :      */
     536           8 :     file = open_auth_file(IdentFileName, ERROR, 0, NULL);
     537             : 
     538           8 :     tokenize_auth_file(IdentFileName, file, &ident_lines, DEBUG3, 0);
     539             : 
     540             :     /* Now parse all the lines */
     541           8 :     identcxt = AllocSetContextCreate(CurrentMemoryContext,
     542             :                                      "ident parser context",
     543             :                                      ALLOCSET_SMALL_SIZES);
     544           8 :     oldcxt = MemoryContextSwitchTo(identcxt);
     545          24 :     foreach(line, ident_lines)
     546             :     {
     547          16 :         TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line);
     548          16 :         IdentLine  *identline = NULL;
     549             : 
     550             :         /* don't parse lines that already have errors */
     551          16 :         if (tok_line->err_msg == NULL)
     552          16 :             identline = parse_ident_line(tok_line, DEBUG3);
     553             : 
     554             :         /* no error, set a new mapping number */
     555          16 :         if (tok_line->err_msg == NULL)
     556          16 :             map_number++;
     557             : 
     558          16 :         fill_ident_line(tuple_store, tupdesc, map_number,
     559             :                         tok_line->file_name, tok_line->line_num,
     560          16 :                         identline, tok_line->err_msg);
     561             :     }
     562             : 
     563             :     /* Free tokenizer memory */
     564           8 :     free_auth_file(file, 0);
     565             :     /* Free parse_ident_line memory */
     566           8 :     MemoryContextSwitchTo(oldcxt);
     567           8 :     MemoryContextDelete(identcxt);
     568           8 : }
     569             : 
     570             : /*
     571             :  * SQL-accessible SRF to return all the entries in the pg_ident.conf file.
     572             :  */
     573             : Datum
     574           8 : pg_ident_file_mappings(PG_FUNCTION_ARGS)
     575             : {
     576             :     ReturnSetInfo *rsi;
     577             : 
     578             :     /*
     579             :      * Build tuplestore to hold the result rows.  We must use the Materialize
     580             :      * mode to be safe against HBA file changes while the cursor is open. It's
     581             :      * also more efficient than having to look up our current position in the
     582             :      * parsed list every time.
     583             :      */
     584           8 :     InitMaterializedSRF(fcinfo, 0);
     585             : 
     586             :     /* Fill the tuplestore */
     587           8 :     rsi = (ReturnSetInfo *) fcinfo->resultinfo;
     588           8 :     fill_ident_view(rsi->setResult, rsi->setDesc);
     589             : 
     590           8 :     PG_RETURN_NULL();
     591             : }

Generated by: LCOV version 1.14