Age Owner Branch data TLA 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 *
1503 michael@paquier.xyz 54 :CBC 37 : get_hba_options(HbaLine *hba)
55 : : {
56 : : int noptions;
57 : : Datum options[MAX_HBA_OPTIONS];
58 : :
59 : 37 : noptions = 0;
60 : :
61 [ + - - + ]: 37 : if (hba->auth_method == uaGSS || hba->auth_method == uaSSPI)
62 : : {
1503 michael@paquier.xyz 63 [ # # ]:UBC 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 : :
1503 michael@paquier.xyz 72 [ - + ]:CBC 37 : if (hba->usermap)
1503 michael@paquier.xyz 73 :UBC 0 : options[noptions++] =
74 : 0 : CStringGetTextDatum(psprintf("map=%s", hba->usermap));
75 : :
1503 michael@paquier.xyz 76 [ - + ]:CBC 37 : if (hba->clientcert != clientCertOff)
1503 michael@paquier.xyz 77 :UBC 0 : options[noptions++] =
78 [ # # ]: 0 : CStringGetTextDatum(psprintf("clientcert=%s", (hba->clientcert == clientCertCA) ? "verify-ca" : "verify-full"));
79 : :
1503 michael@paquier.xyz 80 [ - + ]:CBC 37 : if (hba->pamservice)
1503 michael@paquier.xyz 81 :UBC 0 : options[noptions++] =
82 : 0 : CStringGetTextDatum(psprintf("pamservice=%s", hba->pamservice));
83 : :
1503 michael@paquier.xyz 84 [ - + ]:CBC 37 : if (hba->auth_method == uaLDAP)
85 : : {
1503 michael@paquier.xyz 86 [ # # ]:UBC 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 : :
480 dgustafsson@postgres 94 [ # # ]: 0 : if (hba->ldapscheme)
95 : 0 : options[noptions++] =
96 : 0 : CStringGetTextDatum(psprintf("ldapscheme=%s", hba->ldapscheme));
97 : :
1503 michael@paquier.xyz 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 : :
439 dgustafsson@postgres 138 [ + + ]:CBC 37 : if (hba->auth_method == uaOAuth)
139 : : {
140 [ + - ]: 3 : if (hba->oauth_issuer)
141 : 3 : options[noptions++] =
142 : 3 : CStringGetTextDatum(psprintf("issuer=%s", hba->oauth_issuer));
143 : :
144 [ + - ]: 3 : if (hba->oauth_scope)
145 : 3 : options[noptions++] =
146 : 3 : CStringGetTextDatum(psprintf("scope=%s", hba->oauth_scope));
147 : :
148 [ + - ]: 3 : if (hba->oauth_validator)
149 : 3 : options[noptions++] =
150 : 3 : CStringGetTextDatum(psprintf("validator=%s", hba->oauth_validator));
151 : :
152 [ - + ]: 3 : if (hba->oauth_skip_usermap)
439 dgustafsson@postgres 153 :UBC 0 : options[noptions++] =
154 : 0 : CStringGetTextDatum(psprintf("delegate_ident_mapping=true"));
155 : : }
156 : :
157 : : /* If you add more options, consider increasing MAX_HBA_OPTIONS. */
1503 michael@paquier.xyz 158 [ - + ]:CBC 37 : Assert(noptions <= MAX_HBA_OPTIONS);
159 : :
160 [ + + ]: 37 : if (noptions > 0)
1404 peter@eisentraut.org 161 : 3 : return construct_array_builtin(options, noptions, TEXTOID);
162 : : else
1503 michael@paquier.xyz 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 : 37 : 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 [ - + ]: 37 : Assert(tupdesc->natts == NUM_PG_HBA_FILE_RULES_ATTS);
201 : :
202 : 37 : memset(values, 0, sizeof(values));
203 : 37 : memset(nulls, 0, sizeof(nulls));
204 : 37 : index = 0;
205 : :
206 : : /* rule_number, nothing on error */
1287 207 [ - + ]: 37 : if (err_msg)
1287 michael@paquier.xyz 208 :UBC 0 : nulls[index++] = true;
209 : : else
1287 michael@paquier.xyz 210 :CBC 37 : values[index++] = Int32GetDatum(rule_number);
211 : :
212 : : /* file_name */
1258 213 : 37 : values[index++] = CStringGetTextDatum(filename);
214 : :
215 : : /* line_number */
1503 216 : 37 : values[index++] = Int32GetDatum(lineno);
217 : :
218 [ + - ]: 37 : if (hba != NULL)
219 : : {
220 : : /* type */
221 : : /* Avoid a default: case so compiler will warn about missing cases */
222 : 37 : typestr = NULL;
223 [ + + - - : 37 : switch (hba->conntype)
- - - ]
224 : : {
225 : 21 : case ctLocal:
226 : 21 : typestr = "local";
227 : 21 : break;
228 : 16 : case ctHost:
229 : 16 : typestr = "host";
230 : 16 : break;
1503 michael@paquier.xyz 231 :UBC 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 : : }
1503 michael@paquier.xyz 244 [ + - ]:CBC 37 : if (typestr)
245 : 37 : values[index++] = CStringGetTextDatum(typestr);
246 : : else
1503 michael@paquier.xyz 247 :UBC 0 : nulls[index++] = true;
248 : :
249 : : /* database */
1503 michael@paquier.xyz 250 [ + - ]:CBC 37 : 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 : 37 : List *names = NIL;
261 : :
262 [ + - + + : 75 : foreach(lc, hba->databases)
+ + ]
263 : : {
264 : 38 : AuthToken *tok = lfirst(lc);
265 : :
266 : 38 : names = lappend(names, tok->string);
267 : : }
268 : 37 : values[index++] = PointerGetDatum(strlist_to_textarray(names));
269 : : }
270 : : else
1503 michael@paquier.xyz 271 :UBC 0 : nulls[index++] = true;
272 : :
273 : : /* user */
1503 michael@paquier.xyz 274 [ + - ]:CBC 37 : if (hba->roles)
275 : : {
276 : : /* Flatten AuthToken list to string list; see comment above */
277 : 37 : List *roles = NIL;
278 : :
279 [ + - + + : 74 : foreach(lc, hba->roles)
+ + ]
280 : : {
281 : 37 : AuthToken *tok = lfirst(lc);
282 : :
283 : 37 : roles = lappend(roles, tok->string);
284 : : }
285 : 37 : values[index++] = PointerGetDatum(strlist_to_textarray(roles));
286 : : }
287 : : else
1503 michael@paquier.xyz 288 :UBC 0 : nulls[index++] = true;
289 : :
290 : : /* address and netmask */
291 : : /* Avoid a default: case so compiler will warn about missing cases */
1503 michael@paquier.xyz 292 :CBC 37 : addrstr = maskstr = NULL;
293 [ + - - - : 37 : switch (hba->ip_cmp_method)
- ]
294 : : {
295 : 37 : case ipCmpMask:
296 [ - + ]: 37 : if (hba->hostname)
297 : : {
1503 michael@paquier.xyz 298 :UBC 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 : : */
1503 michael@paquier.xyz 306 [ + + ]:CBC 37 : 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 [ + + ]: 37 : 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 : 37 : break;
1503 michael@paquier.xyz 326 :UBC 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 : : }
1503 michael@paquier.xyz 336 [ + + ]:CBC 37 : if (addrstr)
337 : 16 : values[index++] = CStringGetTextDatum(addrstr);
338 : : else
339 : 21 : nulls[index++] = true;
340 [ + + ]: 37 : if (maskstr)
341 : 16 : values[index++] = CStringGetTextDatum(maskstr);
342 : : else
343 : 21 : nulls[index++] = true;
344 : :
345 : : /* auth_method */
346 : 37 : values[index++] = CStringGetTextDatum(hba_authname(hba->auth_method));
347 : :
348 : : /* options */
349 : 37 : options = get_hba_options(hba);
350 [ + + ]: 37 : if (options)
351 : 3 : 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 */
1258 michael@paquier.xyz 358 :UBC 0 : memset(&nulls[3], true, (NUM_PG_HBA_FILE_RULES_ATTS - 4) * sizeof(bool));
359 : : }
360 : :
361 : : /* error */
1503 michael@paquier.xyz 362 [ - + ]:CBC 37 : if (err_msg)
1503 michael@paquier.xyz 363 :UBC 0 : values[NUM_PG_HBA_FILE_RULES_ATTS - 1] = CStringGetTextDatum(err_msg);
364 : : else
1503 michael@paquier.xyz 365 :CBC 37 : nulls[NUM_PG_HBA_FILE_RULES_ATTS - 1] = true;
366 : :
367 : 37 : tuple = heap_form_tuple(tupdesc, values, nulls);
368 : 37 : tuplestore_puttuple(tuple_store, tuple);
369 : 37 : }
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 : 6 : fill_hba_view(Tuplestorestate *tuple_store, TupleDesc tupdesc)
377 : : {
378 : : FILE *file;
379 : 6 : List *hba_lines = NIL;
380 : : ListCell *line;
1287 381 : 6 : 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 : : */
1268 391 : 6 : file = open_auth_file(HbaFileName, ERROR, 0, NULL);
392 : :
1258 393 : 6 : tokenize_auth_file(HbaFileName, file, &hba_lines, DEBUG3, 0);
394 : :
395 : : /* Now parse all the lines */
1503 396 : 6 : hbacxt = AllocSetContextCreate(CurrentMemoryContext,
397 : : "hba parser context",
398 : : ALLOCSET_SMALL_SIZES);
399 : 6 : oldcxt = MemoryContextSwitchTo(hbacxt);
400 [ + - + + : 43 : foreach(line, hba_lines)
+ + ]
401 : : {
402 : 37 : TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line);
403 : 37 : HbaLine *hbaline = NULL;
404 : :
405 : : /* don't parse lines that already have errors */
406 [ + - ]: 37 : if (tok_line->err_msg == NULL)
407 : 37 : hbaline = parse_hba_line(tok_line, DEBUG3);
408 : :
409 : : /* No error, set a new rule number */
1287 410 [ + - ]: 37 : if (tok_line->err_msg == NULL)
411 : 37 : rule_number++;
412 : :
413 : 37 : fill_hba_line(tuple_store, tupdesc, rule_number,
414 : : tok_line->file_name, tok_line->line_num, hbaline,
1258 415 : 37 : tok_line->err_msg);
416 : : }
417 : :
418 : : /* Free tokenizer memory */
419 : 6 : free_auth_file(file, 0);
420 : : /* Free parse_hba_line memory */
1503 421 : 6 : MemoryContextSwitchTo(oldcxt);
422 : 6 : MemoryContextDelete(hbacxt);
423 : 6 : }
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 : 6 : 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 : : */
1295 442 : 6 : InitMaterializedSRF(fcinfo, 0);
443 : :
444 : : /* Fill the tuplestore */
1503 445 : 6 : rsi = (ReturnSetInfo *) fcinfo->resultinfo;
446 : 6 : fill_hba_view(rsi->setResult, rsi->setDesc);
447 : :
448 : 6 : 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
1498 michael@paquier.xyz 470 :UBC 0 : 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 [ # # ]: 0 : Assert(tupdesc->natts == NUM_PG_IDENT_FILE_MAPPINGS_ATTS);
480 : :
481 : 0 : memset(values, 0, sizeof(values));
482 : 0 : memset(nulls, 0, sizeof(nulls));
483 : 0 : index = 0;
484 : :
485 : : /* map_number, nothing on error */
1287 486 [ # # ]: 0 : if (err_msg)
487 : 0 : nulls[index++] = true;
488 : : else
489 : 0 : values[index++] = Int32GetDatum(map_number);
490 : :
491 : : /* file_name */
1258 492 : 0 : values[index++] = CStringGetTextDatum(filename);
493 : :
494 : : /* line_number */
1498 495 : 0 : values[index++] = Int32GetDatum(lineno);
496 : :
497 [ # # ]: 0 : if (ident != NULL)
498 : : {
499 : 0 : values[index++] = CStringGetTextDatum(ident->usermap);
1209 500 : 0 : values[index++] = CStringGetTextDatum(ident->system_user->string);
1205 501 : 0 : values[index++] = CStringGetTextDatum(ident->pg_user->string);
502 : : }
503 : : else
504 : : {
505 : : /* no parsing result, so set relevant fields to nulls */
1258 506 : 0 : memset(&nulls[3], true, (NUM_PG_IDENT_FILE_MAPPINGS_ATTS - 4) * sizeof(bool));
507 : : }
508 : :
509 : : /* error */
1498 510 [ # # ]: 0 : if (err_msg)
511 : 0 : values[NUM_PG_IDENT_FILE_MAPPINGS_ATTS - 1] = CStringGetTextDatum(err_msg);
512 : : else
513 : 0 : nulls[NUM_PG_IDENT_FILE_MAPPINGS_ATTS - 1] = true;
514 : :
515 : 0 : tuple = heap_form_tuple(tupdesc, values, nulls);
516 : 0 : tuplestore_puttuple(tuple_store, tuple);
517 : 0 : }
518 : :
519 : : /*
520 : : * Read the pg_ident.conf file and fill the tuplestore with view records.
521 : : */
522 : : static void
1498 michael@paquier.xyz 523 :CBC 4 : fill_ident_view(Tuplestorestate *tuple_store, TupleDesc tupdesc)
524 : : {
525 : : FILE *file;
526 : 4 : List *ident_lines = NIL;
527 : : ListCell *line;
1287 528 : 4 : 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 : : */
1268 538 : 4 : file = open_auth_file(IdentFileName, ERROR, 0, NULL);
539 : :
1258 540 : 4 : tokenize_auth_file(IdentFileName, file, &ident_lines, DEBUG3, 0);
541 : :
542 : : /* Now parse all the lines */
1498 543 : 4 : identcxt = AllocSetContextCreate(CurrentMemoryContext,
544 : : "ident parser context",
545 : : ALLOCSET_SMALL_SIZES);
546 : 4 : oldcxt = MemoryContextSwitchTo(identcxt);
547 [ - + - - : 4 : foreach(line, ident_lines)
- + ]
548 : : {
1498 michael@paquier.xyz 549 :UBC 0 : TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line);
550 : 0 : IdentLine *identline = NULL;
551 : :
552 : : /* don't parse lines that already have errors */
553 [ # # ]: 0 : if (tok_line->err_msg == NULL)
554 : 0 : identline = parse_ident_line(tok_line, DEBUG3);
555 : :
556 : : /* no error, set a new mapping number */
1287 557 [ # # ]: 0 : if (tok_line->err_msg == NULL)
558 : 0 : map_number++;
559 : :
560 : 0 : fill_ident_line(tuple_store, tupdesc, map_number,
561 : : tok_line->file_name, tok_line->line_num,
1258 562 : 0 : identline, tok_line->err_msg);
563 : : }
564 : :
565 : : /* Free tokenizer memory */
1258 michael@paquier.xyz 566 :CBC 4 : free_auth_file(file, 0);
567 : : /* Free parse_ident_line memory */
1498 568 : 4 : MemoryContextSwitchTo(oldcxt);
569 : 4 : MemoryContextDelete(identcxt);
570 : 4 : }
571 : :
572 : : /*
573 : : * SQL-accessible SRF to return all the entries in the pg_ident.conf file.
574 : : */
575 : : Datum
576 : 4 : 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 : : */
1295 586 : 4 : InitMaterializedSRF(fcinfo, 0);
587 : :
588 : : /* Fill the tuplestore */
1498 589 : 4 : rsi = (ReturnSetInfo *) fcinfo->resultinfo;
590 : 4 : fill_ident_view(rsi->setResult, rsi->setDesc);
591 : :
592 : 4 : PG_RETURN_NULL();
593 : : }
|