PostgreSQL Source Code git master
Loading...
Searching...
No Matches
hbafuncs.c
Go to the documentation of this file.
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"
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
29static void fill_hba_line(Tuplestorestate *tuple_store, TupleDesc tupdesc,
30 int rule_number, char *filename, int lineno,
31 HbaLine *hba, const char *err_msg);
32static void fill_hba_view(Tuplestorestate *tuple_store, TupleDesc tupdesc);
33static void fill_ident_line(Tuplestorestate *tuple_store, TupleDesc tupdesc,
34 int map_number, char *filename, int lineno,
35 IdentLine *ident, const char *err_msg);
36static 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 */
53static ArrayType *
55{
56 int noptions;
58
59 noptions = 0;
60
61 if (hba->auth_method == uaGSS || hba->auth_method == uaSSPI)
62 {
63 if (hba->include_realm)
64 options[noptions++] =
65 CStringGetTextDatum("include_realm=true");
66
67 if (hba->krb_realm)
68 options[noptions++] =
69 CStringGetTextDatum(psprintf("krb_realm=%s", hba->krb_realm));
70 }
71
72 if (hba->usermap)
73 options[noptions++] =
74 CStringGetTextDatum(psprintf("map=%s", hba->usermap));
75
76 if (hba->clientcert != clientCertOff)
77 options[noptions++] =
78 CStringGetTextDatum(psprintf("clientcert=%s", (hba->clientcert == clientCertCA) ? "verify-ca" : "verify-full"));
79
80 if (hba->pamservice)
81 options[noptions++] =
82 CStringGetTextDatum(psprintf("pamservice=%s", hba->pamservice));
83
84 if (hba->auth_method == uaLDAP)
85 {
86 if (hba->ldapserver)
87 options[noptions++] =
88 CStringGetTextDatum(psprintf("ldapserver=%s", hba->ldapserver));
89
90 if (hba->ldapport)
91 options[noptions++] =
92 CStringGetTextDatum(psprintf("ldapport=%d", hba->ldapport));
93
94 if (hba->ldapscheme)
95 options[noptions++] =
96 CStringGetTextDatum(psprintf("ldapscheme=%s", hba->ldapscheme));
97
98 if (hba->ldaptls)
99 options[noptions++] =
100 CStringGetTextDatum("ldaptls=true");
101
102 if (hba->ldapprefix)
103 options[noptions++] =
104 CStringGetTextDatum(psprintf("ldapprefix=%s", hba->ldapprefix));
105
106 if (hba->ldapsuffix)
107 options[noptions++] =
108 CStringGetTextDatum(psprintf("ldapsuffix=%s", hba->ldapsuffix));
109
110 if (hba->ldapbasedn)
111 options[noptions++] =
112 CStringGetTextDatum(psprintf("ldapbasedn=%s", hba->ldapbasedn));
113
114 if (hba->ldapbinddn)
115 options[noptions++] =
116 CStringGetTextDatum(psprintf("ldapbinddn=%s", hba->ldapbinddn));
117
118 if (hba->ldapbindpasswd)
119 options[noptions++] =
120 CStringGetTextDatum(psprintf("ldapbindpasswd=%s",
121 hba->ldapbindpasswd));
122
123 if (hba->ldapsearchattribute)
124 options[noptions++] =
125 CStringGetTextDatum(psprintf("ldapsearchattribute=%s",
126 hba->ldapsearchattribute));
127
128 if (hba->ldapsearchfilter)
129 options[noptions++] =
130 CStringGetTextDatum(psprintf("ldapsearchfilter=%s",
131 hba->ldapsearchfilter));
132
133 if (hba->ldapscope)
134 options[noptions++] =
135 CStringGetTextDatum(psprintf("ldapscope=%d", hba->ldapscope));
136 }
137
138 if (hba->auth_method == uaOAuth)
139 {
140 if (hba->oauth_issuer)
141 options[noptions++] =
142 CStringGetTextDatum(psprintf("issuer=%s", hba->oauth_issuer));
143
144 if (hba->oauth_scope)
145 options[noptions++] =
146 CStringGetTextDatum(psprintf("scope=%s", hba->oauth_scope));
147
148 if (hba->oauth_validator)
149 options[noptions++] =
150 CStringGetTextDatum(psprintf("validator=%s", hba->oauth_validator));
151
152 if (hba->oauth_skip_usermap)
153 options[noptions++] =
154 CStringGetTextDatum(psprintf("delegate_ident_mapping=true"));
155 }
156
157 /* If you add more options, consider increasing MAX_HBA_OPTIONS. */
159
160 if (noptions > 0)
162 else
163 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 */
184static void
186 int rule_number, char *filename, int lineno, HbaLine *hba,
187 const char *err_msg)
188{
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;
199
201
202 memset(values, 0, sizeof(values));
203 memset(nulls, 0, sizeof(nulls));
204 index = 0;
205
206 /* rule_number, nothing on error */
207 if (err_msg)
208 nulls[index++] = true;
209 else
211
212 /* file_name */
214
215 /* line_number */
216 values[index++] = Int32GetDatum(lineno);
217
218 if (hba != NULL)
219 {
220 /* type */
221 /* Avoid a default: case so compiler will warn about missing cases */
222 typestr = NULL;
223 switch (hba->conntype)
224 {
225 case ctLocal:
226 typestr = "local";
227 break;
228 case ctHost:
229 typestr = "host";
230 break;
231 case ctHostSSL:
232 typestr = "hostssl";
233 break;
234 case ctHostNoSSL:
235 typestr = "hostnossl";
236 break;
237 case ctHostGSS:
238 typestr = "hostgssenc";
239 break;
240 case ctHostNoGSS:
241 typestr = "hostnogssenc";
242 break;
243 }
244 if (typestr)
246 else
247 nulls[index++] = true;
248
249 /* database */
250 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 List *names = NIL;
261
262 foreach(lc, hba->databases)
263 {
265
266 names = lappend(names, tok->string);
267 }
269 }
270 else
271 nulls[index++] = true;
272
273 /* user */
274 if (hba->roles)
275 {
276 /* Flatten AuthToken list to string list; see comment above */
277 List *roles = NIL;
278
279 foreach(lc, hba->roles)
280 {
282
283 roles = lappend(roles, tok->string);
284 }
286 }
287 else
288 nulls[index++] = true;
289
290 /* address and netmask */
291 /* Avoid a default: case so compiler will warn about missing cases */
292 addrstr = maskstr = NULL;
293 switch (hba->ip_cmp_method)
294 {
295 case ipCmpMask:
296 if (hba->hostname)
297 {
298 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 if (hba->addrlen > 0)
307 {
308 if (pg_getnameinfo_all(&hba->addr, hba->addrlen,
309 buffer, sizeof(buffer),
310 NULL, 0,
311 NI_NUMERICHOST) == 0)
312 clean_ipv6_addr(hba->addr.ss_family, buffer);
313 addrstr = pstrdup(buffer);
314 }
315 if (hba->masklen > 0)
316 {
317 if (pg_getnameinfo_all(&hba->mask, hba->masklen,
318 buffer, sizeof(buffer),
319 NULL, 0,
320 NI_NUMERICHOST) == 0)
321 clean_ipv6_addr(hba->mask.ss_family, buffer);
322 maskstr = pstrdup(buffer);
323 }
324 }
325 break;
326 case ipCmpAll:
327 addrstr = "all";
328 break;
329 case ipCmpSameHost:
330 addrstr = "samehost";
331 break;
332 case ipCmpSameNet:
333 addrstr = "samenet";
334 break;
335 }
336 if (addrstr)
338 else
339 nulls[index++] = true;
340 if (maskstr)
342 else
343 nulls[index++] = true;
344
345 /* auth_method */
347
348 /* options */
350 if (options)
352 else
353 nulls[index++] = true;
354 }
355 else
356 {
357 /* no parsing result, so set relevant fields to nulls */
358 memset(&nulls[3], true, (NUM_PG_HBA_FILE_RULES_ATTS - 4) * sizeof(bool));
359 }
360
361 /* error */
362 if (err_msg)
364 else
365 nulls[NUM_PG_HBA_FILE_RULES_ATTS - 1] = true;
366
367 tuple = heap_form_tuple(tupdesc, values, nulls);
368 tuplestore_puttuple(tuple_store, tuple);
369}
370
371/*
372 * fill_hba_view
373 * Read the pg_hba.conf file and fill the tuplestore with view records.
374 */
375static void
377{
378 FILE *file;
379 List *hba_lines = NIL;
380 ListCell *line;
381 int rule_number = 0;
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 */
392
394
395 /* Now parse all the lines */
397 "hba parser context",
400 foreach(line, hba_lines)
401 {
404
405 /* don't parse lines that already have errors */
406 if (tok_line->err_msg == NULL)
408
409 /* No error, set a new rule number */
410 if (tok_line->err_msg == NULL)
411 rule_number++;
412
413 fill_hba_line(tuple_store, tupdesc, rule_number,
414 tok_line->file_name, tok_line->line_num, hbaline,
415 tok_line->err_msg);
416 }
417
418 /* Free tokenizer memory */
419 free_auth_file(file, 0);
420 /* Free parse_hba_line memory */
423}
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 */
431Datum
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 InitMaterializedSRF(fcinfo, 0);
443
444 /* Fill the tuplestore */
445 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
446 fill_hba_view(rsi->setResult, rsi->setDesc);
447
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 */
469static void
471 int map_number, char *filename, int lineno, IdentLine *ident,
472 const char *err_msg)
473{
476 HeapTuple tuple;
477 int index;
478
480
481 memset(values, 0, sizeof(values));
482 memset(nulls, 0, sizeof(nulls));
483 index = 0;
484
485 /* map_number, nothing on error */
486 if (err_msg)
487 nulls[index++] = true;
488 else
490
491 /* file_name */
493
494 /* line_number */
495 values[index++] = Int32GetDatum(lineno);
496
497 if (ident != NULL)
498 {
499 values[index++] = CStringGetTextDatum(ident->usermap);
500 values[index++] = CStringGetTextDatum(ident->system_user->string);
501 values[index++] = CStringGetTextDatum(ident->pg_user->string);
502 }
503 else
504 {
505 /* no parsing result, so set relevant fields to nulls */
506 memset(&nulls[3], true, (NUM_PG_IDENT_FILE_MAPPINGS_ATTS - 4) * sizeof(bool));
507 }
508
509 /* error */
510 if (err_msg)
512 else
513 nulls[NUM_PG_IDENT_FILE_MAPPINGS_ATTS - 1] = true;
514
515 tuple = heap_form_tuple(tupdesc, values, nulls);
516 tuplestore_puttuple(tuple_store, tuple);
517}
518
519/*
520 * Read the pg_ident.conf file and fill the tuplestore with view records.
521 */
522static void
524{
525 FILE *file;
527 ListCell *line;
528 int map_number = 0;
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 */
539
541
542 /* Now parse all the lines */
544 "ident parser context",
547 foreach(line, ident_lines)
548 {
551
552 /* don't parse lines that already have errors */
553 if (tok_line->err_msg == NULL)
555
556 /* no error, set a new mapping number */
557 if (tok_line->err_msg == NULL)
558 map_number++;
559
560 fill_ident_line(tuple_store, tupdesc, map_number,
561 tok_line->file_name, tok_line->line_num,
562 identline, tok_line->err_msg);
563 }
564
565 /* Free tokenizer memory */
566 free_auth_file(file, 0);
567 /* Free parse_ident_line memory */
570}
571
572/*
573 * SQL-accessible SRF to return all the entries in the pg_ident.conf file.
574 */
575Datum
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 InitMaterializedSRF(fcinfo, 0);
587
588 /* Fill the tuplestore */
589 rsi = (ReturnSetInfo *) fcinfo->resultinfo;
591
593}
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
static Datum values[MAXATTR]
Definition bootstrap.c:190
#define CStringGetTextDatum(s)
Definition builtins.h:98
#define Assert(condition)
Definition c.h:943
#define DEBUG3
Definition elog.h:29
#define ERROR
Definition elog.h:40
#define PG_RETURN_NULL()
Definition fmgr.h:346
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
void InitMaterializedSRF(FunctionCallInfo fcinfo, uint32 flags)
Definition funcapi.c:76
char * HbaFileName
Definition guc_tables.c:584
char * IdentFileName
Definition guc_tables.c:585
HbaLine * parse_hba_line(TokenizedAuthLine *tok_line, int elevel)
Definition hba.c:1324
IdentLine * parse_ident_line(TokenizedAuthLine *tok_line, int elevel)
Definition hba.c:2558
void free_auth_file(FILE *file, int depth)
Definition hba.c:568
void tokenize_auth_file(const char *filename, FILE *file, List **tok_lines, int elevel, int depth)
Definition hba.c:687
const char * hba_authname(UserAuth auth_method)
Definition hba.c:2948
FILE * open_auth_file(const char *filename, int elevel, int depth, char **err_msg)
Definition hba.c:593
@ ipCmpAll
Definition hba.h:54
@ ipCmpSameNet
Definition hba.h:53
@ ipCmpMask
Definition hba.h:51
@ ipCmpSameHost
Definition hba.h:52
@ ctHostNoGSS
Definition hba.h:64
@ ctHostSSL
Definition hba.h:61
@ ctHostNoSSL
Definition hba.h:62
@ ctHost
Definition hba.h:60
@ ctHostGSS
Definition hba.h:63
@ ctLocal
Definition hba.h:59
@ uaLDAP
Definition hba.h:38
@ uaGSS
Definition hba.h:34
@ uaOAuth
Definition hba.h:41
@ uaSSPI
Definition hba.h:35
@ clientCertOff
Definition hba.h:69
@ clientCertCA
Definition hba.h:70
static void fill_ident_line(Tuplestorestate *tuple_store, TupleDesc tupdesc, int map_number, char *filename, int lineno, IdentLine *ident, const char *err_msg)
Definition hbafuncs.c:470
static void fill_hba_view(Tuplestorestate *tuple_store, TupleDesc tupdesc)
Definition hbafuncs.c:376
static void fill_ident_view(Tuplestorestate *tuple_store, TupleDesc tupdesc)
Definition hbafuncs.c:523
static void fill_hba_line(Tuplestorestate *tuple_store, TupleDesc tupdesc, int rule_number, char *filename, int lineno, HbaLine *hba, const char *err_msg)
Definition hbafuncs.c:185
#define NUM_PG_HBA_FILE_RULES_ATTS
Definition hbafuncs.c:167
static ArrayType * get_hba_options(HbaLine *hba)
Definition hbafuncs.c:54
Datum pg_ident_file_mappings(PG_FUNCTION_ARGS)
Definition hbafuncs.c:576
#define MAX_HBA_OPTIONS
Definition hbafuncs.c:47
#define NUM_PG_IDENT_FILE_MAPPINGS_ATTS
Definition hbafuncs.c:452
Datum pg_hba_file_rules(PG_FUNCTION_ARGS)
Definition hbafuncs.c:432
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition heaptuple.c:1025
#define ident
int pg_getnameinfo_all(const struct sockaddr_storage *addr, int salen, char *node, int nodelen, char *service, int servicelen, int flags)
Definition ip.c:117
List * lappend(List *list, void *datum)
Definition list.c:339
char * pstrdup(const char *in)
Definition mcxt.c:1781
MemoryContext CurrentMemoryContext
Definition mcxt.c:160
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:472
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition memutils.h:170
void clean_ipv6_addr(int addr_family, char *addr)
Definition network.c:2028
ArrayType * strlist_to_textarray(List *list)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
static char * filename
Definition pg_dumpall.c:133
#define lfirst(lc)
Definition pg_list.h:172
#define NIL
Definition pg_list.h:68
static size_t noptions
uint64_t Datum
Definition postgres.h:70
static Datum Int32GetDatum(int32 X)
Definition postgres.h:212
#define PointerGetDatum(X)
Definition postgres.h:354
static int fb(int x)
char * psprintf(const char *fmt,...)
Definition psprintf.c:43
Definition hba.h:95
UserAuth auth_method
Definition hba.h:108
struct sockaddr_storage mask
Definition hba.h:104
int addrlen
Definition hba.h:103
bool oauth_skip_usermap
Definition hba.h:133
char * ldapserver
Definition hba.h:114
bool include_realm
Definition hba.h:127
int masklen
Definition hba.h:105
ClientCertMode clientcert
Definition hba.h:124
char * ldapsearchfilter
Definition hba.h:119
char * ldapscheme
Definition hba.h:113
char * oauth_issuer
Definition hba.h:130
char * ldapprefix
Definition hba.h:122
char * ldapsearchattribute
Definition hba.h:118
char * krb_realm
Definition hba.h:126
char * ldapbasedn
Definition hba.h:120
char * oauth_scope
Definition hba.h:131
char * oauth_validator
Definition hba.h:132
char * hostname
Definition hba.h:107
char * pamservice
Definition hba.h:110
List * databases
Definition hba.h:100
ConnType conntype
Definition hba.h:99
char * usermap
Definition hba.h:109
char * ldapsuffix
Definition hba.h:123
int ldapport
Definition hba.h:115
struct sockaddr_storage addr
Definition hba.h:102
char * ldapbindpasswd
Definition hba.h:117
List * roles
Definition hba.h:101
char * ldapbinddn
Definition hba.h:116
int ldapscope
Definition hba.h:121
IPCompareMethod ip_cmp_method
Definition hba.h:106
bool ldaptls
Definition hba.h:112
Definition pg_list.h:54
TupleDesc setDesc
Definition execnodes.h:378
Tuplestorestate * setResult
Definition execnodes.h:377
Definition type.h:96
void tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
Definition tuplestore.c:765