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