From a3f02d723274e643741a12c106e9440e7229401d Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Tue, 22 Nov 2022 17:18:05 +0900 Subject: [PATCH v20 2/2] My own changes --- src/include/libpq/hba.h | 6 +- src/backend/libpq/hba.c | 272 ++++++++++++------------- src/backend/libpq/pg_hba.conf.sample | 52 +++-- src/backend/libpq/pg_ident.conf.sample | 31 ++- src/backend/utils/adt/hbafuncs.c | 12 +- src/test/authentication/meson.build | 1 + doc/src/sgml/client-auth.sgml | 109 +++++----- doc/src/sgml/system-views.sgml | 5 +- 8 files changed, 257 insertions(+), 231 deletions(-) diff --git a/src/include/libpq/hba.h b/src/include/libpq/hba.h index a84a5f0961..b1f2d8410d 100644 --- a/src/include/libpq/hba.h +++ b/src/include/libpq/hba.h @@ -179,7 +179,9 @@ extern IdentLine *parse_ident_line(TokenizedAuthLine *tok_line, int elevel); extern bool pg_isblank(const char c); extern FILE *open_auth_file(const char *filename, int elevel, int depth, char **err_msg); -extern MemoryContext tokenize_auth_file(const char *filename, FILE *file, - List **tok_lines, int elevel, int depth); +extern void tokenize_auth_file(const char *filename, FILE *file, + List **tok_lines, int elevel, int depth); +extern void tokenize_init_context(void); +extern void tokenize_reset_context(void); #endif /* HBA_H */ diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c index d5d5c111bc..4382e5a7d1 100644 --- a/src/backend/libpq/hba.c +++ b/src/backend/libpq/hba.c @@ -76,11 +76,12 @@ typedef struct #define token_is_keyword(t, k) (!t->quoted && strcmp(t->string, k) == 0) #define token_matches(t, k) (strcmp(t->string, k) == 0) -typedef enum HbaIncludeKind -{ - SecondaryAuthFile, - IncludedAuthFile -} HbaIncludeKind; +/* + * Memory context holding the list of TokenizedAuthLines when parsing + * HBA or ident config files. This is created at the top point loading + * HBA or ident files. + */ +static MemoryContext tokenize_context = NULL; /* * pre-parsed content of HBA config file: list of HbaLine structs. @@ -127,10 +128,6 @@ static const char *const UserAuthName[] = }; -static void tokenize_file_with_context(MemoryContext linecxt, - const char *filename, FILE *file, - List **tok_lines, int depth, - int elevel); static List *tokenize_inc_file(List *tokens, const char *outer_filename, const char *inc_filename, int elevel, int depth, char **err_msg); @@ -141,10 +138,6 @@ static int regcomp_auth_token(AuthToken *token, char *filename, int line_num, static int regexec_auth_token(const char *match, AuthToken *token, size_t nmatch, regmatch_t pmatch[]); static void tokenize_error_callback(void *arg); -static char *process_included_authfile(const char *inc_filename, bool strict, - const char *outer_filename, int depth, - int elevel, MemoryContext linecxt, - List **tok_lines); /* @@ -485,9 +478,8 @@ tokenize_inc_file(List *tokens, { char *inc_fullname; FILE *inc_file; - List *inc_lines; + List *inc_lines = NIL; ListCell *inc_line; - MemoryContext linecxt; inc_fullname = AbsoluteConfigLocation(inc_filename, outer_filename); inc_file = open_auth_file(inc_fullname, elevel, depth, err_msg); @@ -500,13 +492,16 @@ tokenize_inc_file(List *tokens, } /* There is possible recursion here if the file contains @ */ - linecxt = tokenize_auth_file(inc_fullname, inc_file, &inc_lines, elevel, - depth); + tokenize_auth_file(inc_fullname, inc_file, &inc_lines, elevel, + depth); FreeFile(inc_file); pfree(inc_fullname); - /* Copy all tokens found in the file and append to the tokens list */ + /* + * Move all the tokens found in the file to the tokens list. These + * are already saved in tokenize_context. + */ foreach(inc_line, inc_lines) { TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(inc_line); @@ -528,12 +523,11 @@ tokenize_inc_file(List *tokens, { AuthToken *token = lfirst(inc_token); - tokens = lappend(tokens, copy_auth_token(token)); + tokens = lappend(tokens, token); } } } - MemoryContextDelete(linecxt); return tokens; } @@ -584,6 +578,9 @@ open_auth_file(const char *filename, int elevel, int depth, if (err_msg) *err_msg = psprintf("could not open file \"%s\": %s", filename, strerror(save_errno)); + + /* the caller may care about some specific errno */ + errno = save_errno; return NULL; } @@ -602,40 +599,32 @@ tokenize_error_callback(void *arg) callback_arg->linenum, callback_arg->filename); } -/* - * tokenize_auth_file - * - * Wrapper around tokenize_file_with_context, creating a dedicated memory - * context. - * - * Return value is this memory context which contains all memory allocated by - * this function (it's a child of caller's context). - */ -MemoryContext -tokenize_auth_file(const char *filename, FILE *file, List **tok_lines, - int depth, int elevel) +void +tokenize_init_context(void) { - MemoryContext linecxt; - linecxt = AllocSetContextCreate(CurrentMemoryContext, - "tokenize_auth_file", - ALLOCSET_SMALL_SIZES); + /* + * A context may be present, but assume that it has been eliminated + * already. + * */ + tokenize_context = AllocSetContextCreate(CurrentMemoryContext, + "tokenize_context", + ALLOCSET_START_SMALL_SIZES); +} - *tok_lines = NIL; - - tokenize_file_with_context(linecxt, filename, file, tok_lines, depth, - elevel); - - return linecxt; +void +tokenize_reset_context(void) +{ + MemoryContextDelete(tokenize_context); + tokenize_context = NULL; } /* - * Tokenize the given file. + * tokenize_auth_file + * Tokenize the given file. * * The output is a list of TokenizedAuthLine structs; see the struct definition * in libpq/hba.h. * - * linecxt: memory context which must contain all memory allocated by the - * function * filename: the absolute path to the target file * file: the already-opened target file * tok_lines: receives output list @@ -646,9 +635,9 @@ tokenize_auth_file(const char *filename, FILE *file, List **tok_lines, * adding TokenizedAuthLine structs containing non-null err_msg fields to the * output list. */ -static void -tokenize_file_with_context(MemoryContext linecxt, const char *filename, - FILE *file, List **tok_lines, int elevel, int depth) +void +tokenize_auth_file(const char *filename, FILE *file, List **tok_lines, + int elevel, int depth) { StringInfoData buf; int line_number = 1; @@ -656,6 +645,8 @@ tokenize_file_with_context(MemoryContext linecxt, const char *filename, ErrorContextCallback tokenerrcontext; tokenize_error_callback_arg callback_arg; + Assert(tokenize_context); + callback_arg.filename = filename; callback_arg.linenum = line_number; @@ -664,8 +655,6 @@ tokenize_file_with_context(MemoryContext linecxt, const char *filename, tokenerrcontext.previous = error_context_stack; error_context_stack = &tokenerrcontext; - oldcxt = MemoryContextSwitchTo(linecxt); - initStringInfo(&buf); while (!feof(file) && !ferror(file)) @@ -747,22 +736,31 @@ tokenize_file_with_context(MemoryContext linecxt, const char *filename, if (strcmp(first->string, "include") == 0) { - char *inc_filename; + char *inc_fullname; + FILE *inc_file; - inc_filename = second->string; + inc_fullname = AbsoluteConfigLocation(second->string, filename); + inc_file = open_auth_file(inc_fullname, elevel, depth + 1, + &err_msg); - err_msg = process_included_authfile(inc_filename, true, - filename, depth + 1, elevel, linecxt, - tok_lines); - - if (!err_msg) + if (!inc_file) { - /* - * The line is fully processed, bypass the general - * TokenizedAuthLine processing. - */ - goto next_line; + /* error in err_msg, so create an entry */ + pfree(inc_fullname); + Assert(err_msg); + goto process_line; } + + tokenize_auth_file(inc_fullname, inc_file, tok_lines, elevel, + depth + 1); + FreeFile(inc_file); + pfree(inc_fullname); + + /* + * tokenize_auth_file() has taken care of creating the + * TokenizedAuthLines, so move on. + */ + goto next_line; } else if (strcmp(first->string, "include_dir") == 0) { @@ -776,23 +774,36 @@ tokenize_file_with_context(MemoryContext linecxt, const char *filename, if (!filenames) { - /* We have the error in err_msg, simply process it */ + /* the error is in err_msg, so create an entry */ goto process_line; } initStringInfo(&err_buf); for (int i = 0; i < num_filenames; i++) { - /* - * err_msg is used here as a temp buffer, it will be - * overwritten at the end of the loop with the - * cumulated errors, if any. - */ - err_msg = process_included_authfile(filenames[i], true, - filename, depth + 1, elevel, - linecxt, tok_lines); + char *inc_fullname; + FILE *inc_file; - /* Cumulate errors if any. */ + inc_fullname = AbsoluteConfigLocation(filenames[i], filename); + inc_file = open_auth_file(inc_fullname, elevel, depth + 1, + &err_msg); + + if (!inc_file) + { + /* + * One of the files has failed, so report it + * and ignore the rest. + */ + goto process_line; + } + + tokenize_auth_file(inc_fullname, inc_file, tok_lines, elevel, + depth + 1); + + FreeFile(inc_file); + pfree(inc_fullname); + + /* cumulate errors if any */ if (err_msg) { if (err_buf.len > 0) @@ -810,48 +821,70 @@ tokenize_file_with_context(MemoryContext linecxt, const char *filename, /* Otherwise, process the cumulated errors, if any. */ err_msg = err_buf.data; + goto process_line; } else if (strcmp(first->string, "include_if_exists") == 0) { - char *inc_filename; + char *inc_fullname; + FILE *inc_file; - inc_filename = second->string; + inc_fullname = AbsoluteConfigLocation(second->string, filename); + inc_file = open_auth_file(inc_fullname, elevel, depth + 1, + &err_msg); - err_msg = process_included_authfile(inc_filename, false, - filename, depth + 1, elevel, linecxt, - tok_lines); - - if (!err_msg) + if (!inc_file) { - /* - * The line is fully processed, bypass the general - * TokenizedAuthLine processing. - */ - goto next_line; + if (errno == ENOENT) + { + /* no file, so move to next line */ + + /* XXX: this should stick to elevel for some cases? */ + ereport(LOG, + (errmsg("skipping missing authentication file \"%s\"", + inc_fullname))); + pfree(inc_fullname); + goto next_line; + } + + pfree(inc_fullname); + Assert(err_msg); + goto process_line; } + + tokenize_auth_file(inc_fullname, inc_file, tok_lines, elevel, + depth + 1); + FreeFile(inc_file); + pfree(inc_fullname); + + /* + * tokenize_auth_file() has taken care of creating the + * TokenizedAuthLines. + */ + goto next_line; } } process_line: /* * General processing: report the error if any and emit line to the - * TokenizedAuthLine - */ - tok_line = (TokenizedAuthLine *) palloc(sizeof(TokenizedAuthLine)); + * TokenizedAuthLine. This is saved in the memory context dedicated + * to this list. + */ + oldcxt = MemoryContextSwitchTo(tokenize_context); + tok_line = (TokenizedAuthLine *) palloc0(sizeof(TokenizedAuthLine)); tok_line->fields = current_line; tok_line->file_name = pstrdup(filename); tok_line->line_num = line_number; tok_line->raw_line = pstrdup(buf.data); - tok_line->err_msg = err_msg; + tok_line->err_msg = err_msg ? pstrdup(err_msg) : NULL; *tok_lines = lappend(*tok_lines, tok_line); + MemoryContextSwitchTo(oldcxt); next_line: line_number += continuations + 1; callback_arg.linenum = line_number; } - MemoryContextSwitchTo(oldcxt); - error_context_stack = tokenerrcontext.previous; } @@ -2539,7 +2572,6 @@ load_hba(void) ListCell *line; List *new_parsed_lines = NIL; bool ok = true; - MemoryContext linecxt; MemoryContext oldcxt; MemoryContext hbacxt; @@ -2550,7 +2582,8 @@ load_hba(void) return false; } - linecxt = tokenize_auth_file(HbaFileName, file, &hba_lines, LOG, 0); + tokenize_init_context(); + tokenize_auth_file(HbaFileName, file, &hba_lines, LOG, 0); FreeFile(file); /* Now parse all the lines */ @@ -2602,7 +2635,7 @@ load_hba(void) } /* Free tokenizer memory */ - MemoryContextDelete(linecxt); + tokenize_reset_context(); MemoryContextSwitchTo(oldcxt); if (!ok) @@ -2641,53 +2674,6 @@ load_hba(void) } -/* - * Try to open an included file, and tokenize it using the given context. - * Returns NULL if no error happens during tokenization, otherwise the error. - */ -static char * -process_included_authfile(const char *inc_filename, bool strict, - const char *outer_filename, int depth, int elevel, - MemoryContext linecxt, List **tok_lines) -{ - char *inc_fullname; - FILE *inc_file; - char *err_msg = NULL; - - inc_fullname = AbsoluteConfigLocation(inc_filename, outer_filename); - inc_file = open_auth_file(inc_fullname, elevel, depth, &err_msg); - - if (inc_file == NULL) - { - if (strict) - { - /* open_auth_file should have reported an error. */ - Assert(err_msg != NULL); - return err_msg; - } - else - { - ereport(LOG, - (errmsg("skipping missing authentication file \"%s\"", - inc_fullname))); - return NULL; - } - } - else - { - /* No error message should have been reported. */ - Assert(err_msg == NULL); - } - - tokenize_file_with_context(linecxt, inc_fullname, inc_file, - tok_lines, elevel, depth); - - FreeFile(inc_file); - pfree(inc_fullname); - - return NULL; -} - /* * Parse one tokenised line from the ident config file and store the result in * an IdentLine structure. @@ -2953,7 +2939,6 @@ load_ident(void) *parsed_line_cell; List *new_parsed_lines = NIL; bool ok = true; - MemoryContext linecxt; MemoryContext oldcxt; MemoryContext ident_context; IdentLine *newline; @@ -2966,7 +2951,8 @@ load_ident(void) return false; } - linecxt = tokenize_auth_file(IdentFileName, file, &ident_lines, LOG, 0); + tokenize_init_context(); + tokenize_auth_file(IdentFileName, file, &ident_lines, LOG, 0); FreeFile(file); /* Now parse all the lines */ @@ -3003,7 +2989,7 @@ load_ident(void) } /* Free tokenizer memory */ - MemoryContextDelete(linecxt); + tokenize_reset_context(); MemoryContextSwitchTo(oldcxt); if (!ok) diff --git a/src/backend/libpq/pg_hba.conf.sample b/src/backend/libpq/pg_hba.conf.sample index 7433050112..f72f471d23 100644 --- a/src/backend/libpq/pg_hba.conf.sample +++ b/src/backend/libpq/pg_hba.conf.sample @@ -5,31 +5,24 @@ # documentation for a complete description of this file. A short # synopsis follows. # +# ------------------------------- +# Authentication records +# ------------------------------- +# # This file controls: which hosts are allowed to connect, how clients # are authenticated, which PostgreSQL user names they can use, which # databases they can access. Records take one of these forms: # -# include FILE -# include_if_exists FILE -# include_dir DIRECTORY -# local DATABASE USER METHOD [OPTIONS] -# host DATABASE USER ADDRESS METHOD [OPTIONS] -# hostssl DATABASE USER ADDRESS METHOD [OPTIONS] -# hostnossl DATABASE USER ADDRESS METHOD [OPTIONS] -# hostgssenc DATABASE USER ADDRESS METHOD [OPTIONS] -# hostnogssenc DATABASE USER ADDRESS METHOD [OPTIONS] +# local DATABASE USER METHOD [OPTIONS] +# host DATABASE USER ADDRESS METHOD [OPTIONS] +# hostssl DATABASE USER ADDRESS METHOD [OPTIONS] +# hostnossl DATABASE USER ADDRESS METHOD [OPTIONS] +# hostgssenc DATABASE USER ADDRESS METHOD [OPTIONS] +# hostnogssenc DATABASE USER ADDRESS METHOD [OPTIONS] # # (The uppercase items must be replaced by actual values.) # -# If the first field is "include", "include_if_exists" or "include_dir", it's -# not a mapping record but a directive to include records from respectively -# another file, another file if it exists or all the files in the given -# directory ending in '.conf'. FILE is the file name to include, and -# DIR is the directory name containing the file(s) to include. FILE and -# DIRECTORY can be specified with a relative or absolute path, and can be -# double quoted if they contains spaces. -# -# Otherwise the first field is the connection type: +# The first field is the connection type: # - "local" is a Unix-domain socket # - "host" is a TCP/IP socket (encrypted or not) # - "hostssl" is a TCP/IP socket that is SSL-encrypted @@ -75,11 +68,34 @@ # its special character, and just match a database or username with # that name. # +# -------------------------------- +# Inclusion records +# --------------------------------- +# +# This files allow the inclusion of external files or directories holding +# extra authentication records, using the following keywords: +# +# include FILE +# include_if_exists FILE +# include_dir DIRECTORY +# +# FILE is the file name to include, and DIR is the directory name containing +# the file(s) to include. Any file in a directory will be loaded if suffixed +# with ".conf". The files of a directory are ordered by name. +# include_if_exists ignored missing files. FILE and DIRECTORY can be +# specified as a relative or absolute path, and can be double-quoted if they +# contain spaces. +# +# ------------------------------- +# Miscellaneous +# ------------------------------- +# # This file is read on server startup and when the server receives a # SIGHUP signal. If you edit the file on a running system, you have to # SIGHUP the server for the changes to take effect, run "pg_ctl reload", # or execute "SELECT pg_reload_conf()". # +# --------------------------------- # Put your actual configuration here # ---------------------------------- # diff --git a/src/backend/libpq/pg_ident.conf.sample b/src/backend/libpq/pg_ident.conf.sample index 8e3fa29135..8d9b028aa3 100644 --- a/src/backend/libpq/pg_ident.conf.sample +++ b/src/backend/libpq/pg_ident.conf.sample @@ -1,17 +1,18 @@ # PostgreSQL User Name Maps # ========================= # +# ------------------------------ +# Ident Records +# ------------------------------ +# # Refer to the PostgreSQL documentation, chapter "Client # Authentication" for a complete description. A short synopsis # follows. # # This file controls PostgreSQL user name mapping. It maps external # user names to their corresponding PostgreSQL user names. Records -# are one of these forms: +# are of the form: # -# include FILE -# include_if_exists FILE -# include_dir DIRECTORY # MAPNAME SYSTEM-USERNAME PG-USERNAME # # (The uppercase quantities must be replaced by actual values.) @@ -42,6 +43,28 @@ # system user names and PostgreSQL user names are the same, you don't # need anything in this file. # +# ------------------------------ +# Inclusion records +# ------------------------------ +# +# This files allow the inclusion of external files or directories holding +# extra records, using the following keywords: +# +# include FILE +# include_if_exists FILE +# include_dir DIRECTORY +# +# FILE is the file name to include, and DIR is the directory name containing +# the file(s) to include. Any file in a directory will be loaded if suffixed +# with ".conf". The files of a directory are ordered by name. +# include_if_exists ignored missing files. FILE and DIRECTORY can be +# specified as a relative or absolute path, and can be double-quoted if they +# contain spaces. +# +# ------------------------------- +# Miscellaneous +# ------------------------------- +# # This file is read on server startup and when the postmaster receives # a SIGHUP signal. If you edit the file on a running system, you have # to SIGHUP the postmaster for the changes to take effect. You can diff --git a/src/backend/utils/adt/hbafuncs.c b/src/backend/utils/adt/hbafuncs.c index f9c99d41c6..bab6c3176c 100644 --- a/src/backend/utils/adt/hbafuncs.c +++ b/src/backend/utils/adt/hbafuncs.c @@ -374,7 +374,6 @@ fill_hba_view(Tuplestorestate *tuple_store, TupleDesc tupdesc) List *hba_lines = NIL; ListCell *line; int rule_number = 0; - MemoryContext linecxt; MemoryContext hbacxt; MemoryContext oldcxt; @@ -386,7 +385,8 @@ fill_hba_view(Tuplestorestate *tuple_store, TupleDesc tupdesc) */ file = open_auth_file(HbaFileName, ERROR, 0, NULL); - linecxt = tokenize_auth_file(HbaFileName, file, &hba_lines, DEBUG3, 0); + tokenize_init_context(); + tokenize_auth_file(HbaFileName, file, &hba_lines, DEBUG3, 0); FreeFile(file); /* Now parse all the lines */ @@ -413,7 +413,7 @@ fill_hba_view(Tuplestorestate *tuple_store, TupleDesc tupdesc) } /* Free tokenizer memory */ - MemoryContextDelete(linecxt); + tokenize_reset_context(); /* Free parse_hba_line memory */ MemoryContextSwitchTo(oldcxt); MemoryContextDelete(hbacxt); @@ -523,7 +523,6 @@ fill_ident_view(Tuplestorestate *tuple_store, TupleDesc tupdesc) List *ident_lines = NIL; ListCell *line; int map_number = 0; - MemoryContext linecxt; MemoryContext identcxt; MemoryContext oldcxt; @@ -534,8 +533,9 @@ fill_ident_view(Tuplestorestate *tuple_store, TupleDesc tupdesc) * entry.) */ file = open_auth_file(IdentFileName, ERROR, 0, NULL); + tokenize_init_context(); - linecxt = tokenize_auth_file(IdentFileName, file, &ident_lines, DEBUG3, 0); + tokenize_auth_file(IdentFileName, file, &ident_lines, DEBUG3, 0); FreeFile(file); /* Now parse all the lines */ @@ -562,7 +562,7 @@ fill_ident_view(Tuplestorestate *tuple_store, TupleDesc tupdesc) } /* Free tokenizer memory */ - MemoryContextDelete(linecxt); + tokenize_reset_context(); /* Free parse_ident_line memory */ MemoryContextSwitchTo(oldcxt); MemoryContextDelete(identcxt); diff --git a/src/test/authentication/meson.build b/src/test/authentication/meson.build index c2b48c43c9..cfc23fa213 100644 --- a/src/test/authentication/meson.build +++ b/src/test/authentication/meson.build @@ -7,6 +7,7 @@ tests += { 't/001_password.pl', 't/002_saslprep.pl', 't/003_peer.pl', + 't/004_file_inclusion.pl', ], }, } diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml index 2ae723de66..e5815a5390 100644 --- a/doc/src/sgml/client-auth.sgml +++ b/doc/src/sgml/client-auth.sgml @@ -88,21 +88,6 @@ Backslash line continuation applies even within quoted text or comments. - - Each record can either be an inclusion directive or an authentication - record. Inclusion directives specify files that can be included, which - contains additional records. The records will be inserted in lieu of the - inclusion records. Those records only contains two fields: the - include, include_if_exists or - include_dir directive and the file or directory to be - included. The file or directory can be a relative of absolute path, and can - be double quoted if needed. For the include_dir form, - all files not starting with a . and ending with - .conf will be included. Multiple files within an include - directory are processed in file name order (according to C locale rules, - i.e., numbers before letters, and uppercase letters before lowercase ones). - - Each authentication record specifies a connection type, a client IP address range (if relevant for the connection type), a database name, a user name, @@ -115,12 +100,24 @@ access is denied. + + Each record can be an inclusion directive or an authentication record. + Inclusion directives specify files that can be included, that contain + additional records. The records will be inserted in place of the + inclusion records. Those records only contains two fields: + include, include_if_exists or + include_dir directive and the file or directory to be + included. The file or directory can be a relative of absolute path, and can + be double-quoted. For the include_dir form, all files + not starting with a . and ending with + .conf will be included. Multiple files within an include + directory are processed in file name order (according to C locale rules, + i.e., numbers before letters, and uppercase letters before lowercase ones). + + A record can have several formats: -include file -include_if_exists file -include_dir directory local database user auth-method auth-options host database user address auth-method auth-options hostssl database user address auth-method auth-options @@ -132,43 +129,13 @@ hostssl database userdatabase user IP-address IP-mask auth-method auth-options hostgssenc database user IP-address IP-mask auth-method auth-options hostnogssenc database user IP-address IP-mask auth-method auth-options +include file +include_if_exists file +include_dir directory The meaning of the fields is as follows: - - include - - - This line will be replaced with the content of the given file. - - - - - - include_if_exists - - - This line will be replaced with the content of the given file if the - file exists and can be read. Otherwise, a message will be logged to - indicate that the file is skipped. - - - - - - include_dir - - - This line will be replaced with the content of all the files found in - the directory, if they don't start with a . and end - with .conf, processed in file name order (according - to C locale rules, i.e., numbers before letters, and uppercase letters - before lowercase ones). - - - - local @@ -706,6 +673,39 @@ openssl x509 -in myclient.crt -noout --subject -nameopt RFC2253 | sed "s/^subjec + + + include + + + This line will be replaced by the contents of the given file. + + + + + + include_if_exists + + + This line will be replaced with the content of the given file if the + file exists and can be read. Otherwise, a message will be logged to + indicate that the file is skipped. + + + + + + include_dir + + + This line will be replaced with the content of all the files found in + the directory, if they don't start with a . and end + with .conf, processed in file name order (according + to C locale rules, i.e., numbers before letters, and uppercase letters + before lowercase ones). + + + @@ -916,9 +916,9 @@ local db1,db2,@demodbs all md5 configuration parameter.) The ident map file contains lines of two general form: +map-name system-username database-username include file include_dir directory -map-name system-username database-username Comments, whitespace and line continuations are handled in the same way as in pg_hba.conf. The @@ -929,9 +929,8 @@ local db1,db2,@demodbs all md5 used repeatedly to specify multiple user-mappings within a single map. - As for pg_hba.conf, the lines in this file can either - be inclusion directives or user name map records, and follow the same - rules. + As for pg_hba.conf, the lines in this file can + be inclusion directives, following the same rules. There is no restriction regarding how many database users a given diff --git a/doc/src/sgml/system-views.sgml b/doc/src/sgml/system-views.sgml index a21c3fee15..d38b42c5cd 100644 --- a/doc/src/sgml/system-views.sgml +++ b/doc/src/sgml/system-views.sgml @@ -1016,7 +1016,7 @@ line_number int4 - Line number of this rule the given file_name + Line number of this rule in file_name @@ -1175,8 +1175,7 @@ line_number int4 - Line number of this map in the corresponding - file_name + Line number of this map in file_name -- 2.38.1