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