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