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-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 *
1262 michael@paquier.xyz 52 :CBC 31 : get_hba_options(HbaLine *hba)
53 : : {
54 : : int noptions;
55 : : Datum options[MAX_HBA_OPTIONS];
56 : :
57 : 31 : noptions = 0;
58 : :
59 [ + - - + ]: 31 : if (hba->auth_method == uaGSS || hba->auth_method == uaSSPI)
60 : : {
1262 michael@paquier.xyz 61 [ # # ]:UBC 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 : :
1262 michael@paquier.xyz 70 [ - + ]:CBC 31 : if (hba->usermap)
1262 michael@paquier.xyz 71 :UBC 0 : options[noptions++] =
72 : 0 : CStringGetTextDatum(psprintf("map=%s", hba->usermap));
73 : :
1262 michael@paquier.xyz 74 [ - + ]:CBC 31 : if (hba->clientcert != clientCertOff)
1262 michael@paquier.xyz 75 :UBC 0 : options[noptions++] =
76 [ # # ]: 0 : CStringGetTextDatum(psprintf("clientcert=%s", (hba->clientcert == clientCertCA) ? "verify-ca" : "verify-full"));
77 : :
1262 michael@paquier.xyz 78 [ - + ]:CBC 31 : if (hba->pamservice)
1262 michael@paquier.xyz 79 :UBC 0 : options[noptions++] =
80 : 0 : CStringGetTextDatum(psprintf("pamservice=%s", hba->pamservice));
81 : :
1262 michael@paquier.xyz 82 [ - + ]:CBC 31 : if (hba->auth_method == uaLDAP)
83 : : {
1262 michael@paquier.xyz 84 [ # # ]:UBC 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 : :
239 dgustafsson@postgres 92 [ # # ]: 0 : if (hba->ldapscheme)
93 : 0 : options[noptions++] =
94 : 0 : CStringGetTextDatum(psprintf("ldapscheme=%s", hba->ldapscheme));
95 : :
1262 michael@paquier.xyz 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 : :
1262 michael@paquier.xyz 136 [ - + ]:CBC 31 : if (hba->auth_method == uaRADIUS)
137 : : {
1262 michael@paquier.xyz 138 [ # # ]:UBC 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 : :
198 dgustafsson@postgres 155 [ + + ]:CBC 31 : if (hba->auth_method == uaOAuth)
156 : : {
157 [ + - ]: 3 : if (hba->oauth_issuer)
158 : 3 : options[noptions++] =
159 : 3 : CStringGetTextDatum(psprintf("issuer=%s", hba->oauth_issuer));
160 : :
161 [ + - ]: 3 : if (hba->oauth_scope)
162 : 3 : options[noptions++] =
163 : 3 : CStringGetTextDatum(psprintf("scope=%s", hba->oauth_scope));
164 : :
165 [ + - ]: 3 : if (hba->oauth_validator)
166 : 3 : options[noptions++] =
167 : 3 : CStringGetTextDatum(psprintf("validator=%s", hba->oauth_validator));
168 : :
169 [ - + ]: 3 : if (hba->oauth_skip_usermap)
198 dgustafsson@postgres 170 :UBC 0 : options[noptions++] =
171 : 0 : CStringGetTextDatum(psprintf("delegate_ident_mapping=true"));
172 : : }
173 : :
174 : : /* If you add more options, consider increasing MAX_HBA_OPTIONS. */
1262 michael@paquier.xyz 175 [ - + ]:CBC 31 : Assert(noptions <= MAX_HBA_OPTIONS);
176 : :
177 [ + + ]: 31 : if (noptions > 0)
1163 peter@eisentraut.org 178 : 3 : return construct_array_builtin(options, noptions, TEXTOID);
179 : : else
1262 michael@paquier.xyz 180 : 28 : return NULL;
181 : : }
182 : :
183 : : /* Number of columns in pg_hba_file_rules view */
184 : : #define NUM_PG_HBA_FILE_RULES_ATTS 11
185 : :
186 : : /*
187 : : * fill_hba_line
188 : : * Build one row of pg_hba_file_rules view, add it to tuplestore.
189 : : *
190 : : * tuple_store: where to store data
191 : : * tupdesc: tuple descriptor for the view
192 : : * rule_number: unique identifier among all valid rules
193 : : * filename: configuration file name (must always be valid)
194 : : * lineno: line number of configuration file (must always be valid)
195 : : * hba: parsed line data (can be NULL, in which case err_msg should be set)
196 : : * err_msg: error message (NULL if none)
197 : : *
198 : : * Note: leaks memory, but we don't care since this is run in a short-lived
199 : : * memory context.
200 : : */
201 : : static void
202 : 31 : fill_hba_line(Tuplestorestate *tuple_store, TupleDesc tupdesc,
203 : : int rule_number, char *filename, int lineno, HbaLine *hba,
204 : : const char *err_msg)
205 : : {
206 : : Datum values[NUM_PG_HBA_FILE_RULES_ATTS];
207 : : bool nulls[NUM_PG_HBA_FILE_RULES_ATTS];
208 : : char buffer[NI_MAXHOST];
209 : : HeapTuple tuple;
210 : : int index;
211 : : ListCell *lc;
212 : : const char *typestr;
213 : : const char *addrstr;
214 : : const char *maskstr;
215 : : ArrayType *options;
216 : :
217 [ - + ]: 31 : Assert(tupdesc->natts == NUM_PG_HBA_FILE_RULES_ATTS);
218 : :
219 : 31 : memset(values, 0, sizeof(values));
220 : 31 : memset(nulls, 0, sizeof(nulls));
221 : 31 : index = 0;
222 : :
223 : : /* rule_number, nothing on error */
1046 224 [ - + ]: 31 : if (err_msg)
1046 michael@paquier.xyz 225 :UBC 0 : nulls[index++] = true;
226 : : else
1046 michael@paquier.xyz 227 :CBC 31 : values[index++] = Int32GetDatum(rule_number);
228 : :
229 : : /* file_name */
1017 230 : 31 : values[index++] = CStringGetTextDatum(filename);
231 : :
232 : : /* line_number */
1262 233 : 31 : values[index++] = Int32GetDatum(lineno);
234 : :
235 [ + - ]: 31 : if (hba != NULL)
236 : : {
237 : : /* type */
238 : : /* Avoid a default: case so compiler will warn about missing cases */
239 : 31 : typestr = NULL;
240 [ + + - - : 31 : switch (hba->conntype)
- - - ]
241 : : {
242 : 19 : case ctLocal:
243 : 19 : typestr = "local";
244 : 19 : break;
245 : 12 : case ctHost:
246 : 12 : typestr = "host";
247 : 12 : break;
1262 michael@paquier.xyz 248 :UBC 0 : case ctHostSSL:
249 : 0 : typestr = "hostssl";
250 : 0 : break;
251 : 0 : case ctHostNoSSL:
252 : 0 : typestr = "hostnossl";
253 : 0 : break;
254 : 0 : case ctHostGSS:
255 : 0 : typestr = "hostgssenc";
256 : 0 : break;
257 : 0 : case ctHostNoGSS:
258 : 0 : typestr = "hostnogssenc";
259 : 0 : break;
260 : : }
1262 michael@paquier.xyz 261 [ + - ]:CBC 31 : if (typestr)
262 : 31 : values[index++] = CStringGetTextDatum(typestr);
263 : : else
1262 michael@paquier.xyz 264 :UBC 0 : nulls[index++] = true;
265 : :
266 : : /* database */
1262 michael@paquier.xyz 267 [ + - ]:CBC 31 : if (hba->databases)
268 : : {
269 : : /*
270 : : * Flatten AuthToken list to string list. It might seem that we
271 : : * should re-quote any quoted tokens, but that has been rejected
272 : : * on the grounds that it makes it harder to compare the array
273 : : * elements to other system catalogs. That makes entries like
274 : : * "all" or "samerole" formally ambiguous ... but users who name
275 : : * databases/roles that way are inflicting their own pain.
276 : : */
277 : 31 : List *names = NIL;
278 : :
279 [ + - + + : 63 : foreach(lc, hba->databases)
+ + ]
280 : : {
281 : 32 : AuthToken *tok = lfirst(lc);
282 : :
283 : 32 : names = lappend(names, tok->string);
284 : : }
285 : 31 : values[index++] = PointerGetDatum(strlist_to_textarray(names));
286 : : }
287 : : else
1262 michael@paquier.xyz 288 :UBC 0 : nulls[index++] = true;
289 : :
290 : : /* user */
1262 michael@paquier.xyz 291 [ + - ]:CBC 31 : if (hba->roles)
292 : : {
293 : : /* Flatten AuthToken list to string list; see comment above */
294 : 31 : List *roles = NIL;
295 : :
296 [ + - + + : 62 : foreach(lc, hba->roles)
+ + ]
297 : : {
298 : 31 : AuthToken *tok = lfirst(lc);
299 : :
300 : 31 : roles = lappend(roles, tok->string);
301 : : }
302 : 31 : values[index++] = PointerGetDatum(strlist_to_textarray(roles));
303 : : }
304 : : else
1262 michael@paquier.xyz 305 :UBC 0 : nulls[index++] = true;
306 : :
307 : : /* address and netmask */
308 : : /* Avoid a default: case so compiler will warn about missing cases */
1262 michael@paquier.xyz 309 :CBC 31 : addrstr = maskstr = NULL;
310 [ + - - - : 31 : switch (hba->ip_cmp_method)
- ]
311 : : {
312 : 31 : case ipCmpMask:
313 [ - + ]: 31 : if (hba->hostname)
314 : : {
1262 michael@paquier.xyz 315 :UBC 0 : addrstr = hba->hostname;
316 : : }
317 : : else
318 : : {
319 : : /*
320 : : * Note: if pg_getnameinfo_all fails, it'll set buffer to
321 : : * "???", which we want to return.
322 : : */
1262 michael@paquier.xyz 323 [ + + ]:CBC 31 : if (hba->addrlen > 0)
324 : : {
325 [ + - ]: 12 : if (pg_getnameinfo_all(&hba->addr, hba->addrlen,
326 : : buffer, sizeof(buffer),
327 : : NULL, 0,
328 : : NI_NUMERICHOST) == 0)
329 : 12 : clean_ipv6_addr(hba->addr.ss_family, buffer);
330 : 12 : addrstr = pstrdup(buffer);
331 : : }
332 [ + + ]: 31 : if (hba->masklen > 0)
333 : : {
334 [ + - ]: 12 : if (pg_getnameinfo_all(&hba->mask, hba->masklen,
335 : : buffer, sizeof(buffer),
336 : : NULL, 0,
337 : : NI_NUMERICHOST) == 0)
338 : 12 : clean_ipv6_addr(hba->mask.ss_family, buffer);
339 : 12 : maskstr = pstrdup(buffer);
340 : : }
341 : : }
342 : 31 : break;
1262 michael@paquier.xyz 343 :UBC 0 : case ipCmpAll:
344 : 0 : addrstr = "all";
345 : 0 : break;
346 : 0 : case ipCmpSameHost:
347 : 0 : addrstr = "samehost";
348 : 0 : break;
349 : 0 : case ipCmpSameNet:
350 : 0 : addrstr = "samenet";
351 : 0 : break;
352 : : }
1262 michael@paquier.xyz 353 [ + + ]:CBC 31 : if (addrstr)
354 : 12 : values[index++] = CStringGetTextDatum(addrstr);
355 : : else
356 : 19 : nulls[index++] = true;
357 [ + + ]: 31 : if (maskstr)
358 : 12 : values[index++] = CStringGetTextDatum(maskstr);
359 : : else
360 : 19 : nulls[index++] = true;
361 : :
362 : : /* auth_method */
363 : 31 : values[index++] = CStringGetTextDatum(hba_authname(hba->auth_method));
364 : :
365 : : /* options */
366 : 31 : options = get_hba_options(hba);
367 [ + + ]: 31 : if (options)
368 : 3 : values[index++] = PointerGetDatum(options);
369 : : else
370 : 28 : nulls[index++] = true;
371 : : }
372 : : else
373 : : {
374 : : /* no parsing result, so set relevant fields to nulls */
1017 michael@paquier.xyz 375 :UBC 0 : memset(&nulls[3], true, (NUM_PG_HBA_FILE_RULES_ATTS - 4) * sizeof(bool));
376 : : }
377 : :
378 : : /* error */
1262 michael@paquier.xyz 379 [ - + ]:CBC 31 : if (err_msg)
1262 michael@paquier.xyz 380 :UBC 0 : values[NUM_PG_HBA_FILE_RULES_ATTS - 1] = CStringGetTextDatum(err_msg);
381 : : else
1262 michael@paquier.xyz 382 :CBC 31 : nulls[NUM_PG_HBA_FILE_RULES_ATTS - 1] = true;
383 : :
384 : 31 : tuple = heap_form_tuple(tupdesc, values, nulls);
385 : 31 : tuplestore_puttuple(tuple_store, tuple);
386 : 31 : }
387 : :
388 : : /*
389 : : * fill_hba_view
390 : : * Read the pg_hba.conf file and fill the tuplestore with view records.
391 : : */
392 : : static void
393 : 5 : fill_hba_view(Tuplestorestate *tuple_store, TupleDesc tupdesc)
394 : : {
395 : : FILE *file;
396 : 5 : List *hba_lines = NIL;
397 : : ListCell *line;
1046 398 : 5 : int rule_number = 0;
399 : : MemoryContext hbacxt;
400 : : MemoryContext oldcxt;
401 : :
402 : : /*
403 : : * In the unlikely event that we can't open pg_hba.conf, we throw an
404 : : * error, rather than trying to report it via some sort of view entry.
405 : : * (Most other error conditions should result in a message in a view
406 : : * entry.)
407 : : */
1027 408 : 5 : file = open_auth_file(HbaFileName, ERROR, 0, NULL);
409 : :
1017 410 : 5 : tokenize_auth_file(HbaFileName, file, &hba_lines, DEBUG3, 0);
411 : :
412 : : /* Now parse all the lines */
1262 413 : 5 : hbacxt = AllocSetContextCreate(CurrentMemoryContext,
414 : : "hba parser context",
415 : : ALLOCSET_SMALL_SIZES);
416 : 5 : oldcxt = MemoryContextSwitchTo(hbacxt);
417 [ + - + + : 36 : foreach(line, hba_lines)
+ + ]
418 : : {
419 : 31 : TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line);
420 : 31 : HbaLine *hbaline = NULL;
421 : :
422 : : /* don't parse lines that already have errors */
423 [ + - ]: 31 : if (tok_line->err_msg == NULL)
424 : 31 : hbaline = parse_hba_line(tok_line, DEBUG3);
425 : :
426 : : /* No error, set a new rule number */
1046 427 [ + - ]: 31 : if (tok_line->err_msg == NULL)
428 : 31 : rule_number++;
429 : :
430 : 31 : fill_hba_line(tuple_store, tupdesc, rule_number,
431 : : tok_line->file_name, tok_line->line_num, hbaline,
1017 432 : 31 : tok_line->err_msg);
433 : : }
434 : :
435 : : /* Free tokenizer memory */
436 : 5 : free_auth_file(file, 0);
437 : : /* Free parse_hba_line memory */
1262 438 : 5 : MemoryContextSwitchTo(oldcxt);
439 : 5 : MemoryContextDelete(hbacxt);
440 : 5 : }
441 : :
442 : : /*
443 : : * pg_hba_file_rules
444 : : *
445 : : * SQL-accessible set-returning function to return all the entries in the
446 : : * pg_hba.conf file.
447 : : */
448 : : Datum
449 : 5 : pg_hba_file_rules(PG_FUNCTION_ARGS)
450 : : {
451 : : ReturnSetInfo *rsi;
452 : :
453 : : /*
454 : : * Build tuplestore to hold the result rows. We must use the Materialize
455 : : * mode to be safe against HBA file changes while the cursor is open. It's
456 : : * also more efficient than having to look up our current position in the
457 : : * parsed list every time.
458 : : */
1054 459 : 5 : InitMaterializedSRF(fcinfo, 0);
460 : :
461 : : /* Fill the tuplestore */
1262 462 : 5 : rsi = (ReturnSetInfo *) fcinfo->resultinfo;
463 : 5 : fill_hba_view(rsi->setResult, rsi->setDesc);
464 : :
465 : 5 : PG_RETURN_NULL();
466 : : }
467 : :
468 : : /* Number of columns in pg_ident_file_mappings view */
469 : : #define NUM_PG_IDENT_FILE_MAPPINGS_ATTS 7
470 : :
471 : : /*
472 : : * fill_ident_line: build one row of pg_ident_file_mappings view, add it to
473 : : * tuplestore
474 : : *
475 : : * tuple_store: where to store data
476 : : * tupdesc: tuple descriptor for the view
477 : : * map_number: unique identifier among all valid maps
478 : : * filename: configuration file name (must always be valid)
479 : : * lineno: line number of configuration file (must always be valid)
480 : : * ident: parsed line data (can be NULL, in which case err_msg should be set)
481 : : * err_msg: error message (NULL if none)
482 : : *
483 : : * Note: leaks memory, but we don't care since this is run in a short-lived
484 : : * memory context.
485 : : */
486 : : static void
1257 michael@paquier.xyz 487 :UBC 0 : fill_ident_line(Tuplestorestate *tuple_store, TupleDesc tupdesc,
488 : : int map_number, char *filename, int lineno, IdentLine *ident,
489 : : const char *err_msg)
490 : : {
491 : : Datum values[NUM_PG_IDENT_FILE_MAPPINGS_ATTS];
492 : : bool nulls[NUM_PG_IDENT_FILE_MAPPINGS_ATTS];
493 : : HeapTuple tuple;
494 : : int index;
495 : :
496 [ # # ]: 0 : Assert(tupdesc->natts == NUM_PG_IDENT_FILE_MAPPINGS_ATTS);
497 : :
498 : 0 : memset(values, 0, sizeof(values));
499 : 0 : memset(nulls, 0, sizeof(nulls));
500 : 0 : index = 0;
501 : :
502 : : /* map_number, nothing on error */
1046 503 [ # # ]: 0 : if (err_msg)
504 : 0 : nulls[index++] = true;
505 : : else
506 : 0 : values[index++] = Int32GetDatum(map_number);
507 : :
508 : : /* file_name */
1017 509 : 0 : values[index++] = CStringGetTextDatum(filename);
510 : :
511 : : /* line_number */
1257 512 : 0 : values[index++] = Int32GetDatum(lineno);
513 : :
514 [ # # ]: 0 : if (ident != NULL)
515 : : {
516 : 0 : values[index++] = CStringGetTextDatum(ident->usermap);
968 517 : 0 : values[index++] = CStringGetTextDatum(ident->system_user->string);
964 518 : 0 : values[index++] = CStringGetTextDatum(ident->pg_user->string);
519 : : }
520 : : else
521 : : {
522 : : /* no parsing result, so set relevant fields to nulls */
1017 523 : 0 : memset(&nulls[3], true, (NUM_PG_IDENT_FILE_MAPPINGS_ATTS - 4) * sizeof(bool));
524 : : }
525 : :
526 : : /* error */
1257 527 [ # # ]: 0 : if (err_msg)
528 : 0 : values[NUM_PG_IDENT_FILE_MAPPINGS_ATTS - 1] = CStringGetTextDatum(err_msg);
529 : : else
530 : 0 : nulls[NUM_PG_IDENT_FILE_MAPPINGS_ATTS - 1] = true;
531 : :
532 : 0 : tuple = heap_form_tuple(tupdesc, values, nulls);
533 : 0 : tuplestore_puttuple(tuple_store, tuple);
534 : 0 : }
535 : :
536 : : /*
537 : : * Read the pg_ident.conf file and fill the tuplestore with view records.
538 : : */
539 : : static void
1257 michael@paquier.xyz 540 :CBC 3 : fill_ident_view(Tuplestorestate *tuple_store, TupleDesc tupdesc)
541 : : {
542 : : FILE *file;
543 : 3 : List *ident_lines = NIL;
544 : : ListCell *line;
1046 545 : 3 : int map_number = 0;
546 : : MemoryContext identcxt;
547 : : MemoryContext oldcxt;
548 : :
549 : : /*
550 : : * In the unlikely event that we can't open pg_ident.conf, we throw an
551 : : * error, rather than trying to report it via some sort of view entry.
552 : : * (Most other error conditions should result in a message in a view
553 : : * entry.)
554 : : */
1027 555 : 3 : file = open_auth_file(IdentFileName, ERROR, 0, NULL);
556 : :
1017 557 : 3 : tokenize_auth_file(IdentFileName, file, &ident_lines, DEBUG3, 0);
558 : :
559 : : /* Now parse all the lines */
1257 560 : 3 : identcxt = AllocSetContextCreate(CurrentMemoryContext,
561 : : "ident parser context",
562 : : ALLOCSET_SMALL_SIZES);
563 : 3 : oldcxt = MemoryContextSwitchTo(identcxt);
564 [ - + - - : 3 : foreach(line, ident_lines)
- + ]
565 : : {
1257 michael@paquier.xyz 566 :UBC 0 : TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line);
567 : 0 : IdentLine *identline = NULL;
568 : :
569 : : /* don't parse lines that already have errors */
570 [ # # ]: 0 : if (tok_line->err_msg == NULL)
571 : 0 : identline = parse_ident_line(tok_line, DEBUG3);
572 : :
573 : : /* no error, set a new mapping number */
1046 574 [ # # ]: 0 : if (tok_line->err_msg == NULL)
575 : 0 : map_number++;
576 : :
577 : 0 : fill_ident_line(tuple_store, tupdesc, map_number,
578 : : tok_line->file_name, tok_line->line_num,
1017 579 : 0 : identline, tok_line->err_msg);
580 : : }
581 : :
582 : : /* Free tokenizer memory */
1017 michael@paquier.xyz 583 :CBC 3 : free_auth_file(file, 0);
584 : : /* Free parse_ident_line memory */
1257 585 : 3 : MemoryContextSwitchTo(oldcxt);
586 : 3 : MemoryContextDelete(identcxt);
587 : 3 : }
588 : :
589 : : /*
590 : : * SQL-accessible SRF to return all the entries in the pg_ident.conf file.
591 : : */
592 : : Datum
593 : 3 : pg_ident_file_mappings(PG_FUNCTION_ARGS)
594 : : {
595 : : ReturnSetInfo *rsi;
596 : :
597 : : /*
598 : : * Build tuplestore to hold the result rows. We must use the Materialize
599 : : * mode to be safe against HBA file changes while the cursor is open. It's
600 : : * also more efficient than having to look up our current position in the
601 : : * parsed list every time.
602 : : */
1054 603 : 3 : InitMaterializedSRF(fcinfo, 0);
604 : :
605 : : /* Fill the tuplestore */
1257 606 : 3 : rsi = (ReturnSetInfo *) fcinfo->resultinfo;
607 : 3 : fill_ident_view(rsi->setResult, rsi->setDesc);
608 : :
609 : 3 : PG_RETURN_NULL();
610 : : }
|