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

Generated by: LCOV version 2.0-1