00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "postgres.h"
00018
00019 #include <ctype.h>
00020 #include <pwd.h>
00021 #include <fcntl.h>
00022 #include <sys/param.h>
00023 #include <sys/socket.h>
00024 #include <netinet/in.h>
00025 #include <arpa/inet.h>
00026 #include <unistd.h>
00027
00028 #include "catalog/pg_collation.h"
00029 #include "libpq/ip.h"
00030 #include "libpq/libpq.h"
00031 #include "postmaster/postmaster.h"
00032 #include "regex/regex.h"
00033 #include "replication/walsender.h"
00034 #include "storage/fd.h"
00035 #include "utils/acl.h"
00036 #include "utils/guc.h"
00037 #include "utils/lsyscache.h"
00038 #include "utils/memutils.h"
00039
00040 #ifdef USE_LDAP
00041 #ifdef WIN32
00042 #include <winldap.h>
00043 #else
00044 #include <ldap.h>
00045 #endif
00046 #endif
00047
00048
00049 #define atooid(x) ((Oid) strtoul((x), NULL, 10))
00050 #define atoxid(x) ((TransactionId) strtoul((x), NULL, 10))
00051
00052 #define MAX_TOKEN 256
00053 #define MAX_LINE 8192
00054
00055
00056 typedef struct check_network_data
00057 {
00058 IPCompareMethod method;
00059 SockAddr *raddr;
00060 bool result;
00061 } check_network_data;
00062
00063
00064 #define token_is_keyword(t, k) (!t->quoted && strcmp(t->string, k) == 0)
00065 #define token_matches(t, k) (strcmp(t->string, k) == 0)
00066
00067
00068
00069
00070
00071 typedef struct HbaToken
00072 {
00073 char *string;
00074 bool quoted;
00075 } HbaToken;
00076
00077
00078
00079
00080
00081 static List *parsed_hba_lines = NIL;
00082 static MemoryContext parsed_hba_context = NULL;
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092 static List *parsed_ident_lines = NIL;
00093 static MemoryContext parsed_ident_context = NULL;
00094
00095
00096 static MemoryContext tokenize_file(const char *filename, FILE *file,
00097 List **lines, List **line_nums, List **raw_lines);
00098 static List *tokenize_inc_file(List *tokens, const char *outer_filename,
00099 const char *inc_filename);
00100 static bool parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline,
00101 int line_num);
00102
00103
00104
00105
00106
00107 bool
00108 pg_isblank(const char c)
00109 {
00110 return c == ' ' || c == '\t' || c == '\r';
00111 }
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138 static bool
00139 next_token(char **lineptr, char *buf, int bufsz, bool *initial_quote,
00140 bool *terminating_comma)
00141 {
00142 int c;
00143 char *start_buf = buf;
00144 char *end_buf = buf + (bufsz - 2);
00145 bool in_quote = false;
00146 bool was_quote = false;
00147 bool saw_quote = false;
00148
00149
00150 Assert(end_buf > start_buf);
00151
00152 *initial_quote = false;
00153 *terminating_comma = false;
00154
00155
00156 while ((c = (*(*lineptr)++)) != '\0' && (pg_isblank(c) || c == ','))
00157 ;
00158
00159 if (c == '\0' || c == '\n')
00160 {
00161 *buf = '\0';
00162 return false;
00163 }
00164
00165
00166
00167
00168
00169 while (c != '\0' && c != '\n' &&
00170 (!pg_isblank(c) || in_quote))
00171 {
00172
00173 if (c == '#' && !in_quote)
00174 {
00175 while ((c = (*(*lineptr)++)) != '\0' && c != '\n')
00176 ;
00177
00178 if (c != '\0' && buf == start_buf)
00179 (*lineptr)++;
00180 break;
00181 }
00182
00183 if (buf >= end_buf)
00184 {
00185 *buf = '\0';
00186 ereport(LOG,
00187 (errcode(ERRCODE_CONFIG_FILE_ERROR),
00188 errmsg("authentication file token too long, skipping: \"%s\"",
00189 start_buf)));
00190
00191 while ((c = (*(*lineptr)++)) != '\0' && c != '\n')
00192 ;
00193 break;
00194 }
00195
00196
00197 if (c == ',' && !in_quote)
00198 {
00199 *terminating_comma = true;
00200 break;
00201 }
00202
00203 if (c != '"' || was_quote)
00204 *buf++ = c;
00205
00206
00207 if (in_quote && c == '"')
00208 was_quote = !was_quote;
00209 else
00210 was_quote = false;
00211
00212 if (c == '"')
00213 {
00214 in_quote = !in_quote;
00215 saw_quote = true;
00216 if (buf == start_buf)
00217 *initial_quote = true;
00218 }
00219
00220 c = *(*lineptr)++;
00221 }
00222
00223
00224
00225
00226
00227 (*lineptr)--;
00228
00229 *buf = '\0';
00230
00231 return (saw_quote || buf > start_buf);
00232 }
00233
00234 static HbaToken *
00235 make_hba_token(char *token, bool quoted)
00236 {
00237 HbaToken *hbatoken;
00238 int toklen;
00239
00240 toklen = strlen(token);
00241 hbatoken = (HbaToken *) palloc(sizeof(HbaToken) + toklen + 1);
00242 hbatoken->string = (char *) hbatoken + sizeof(HbaToken);
00243 hbatoken->quoted = quoted;
00244 memcpy(hbatoken->string, token, toklen + 1);
00245
00246 return hbatoken;
00247 }
00248
00249
00250
00251
00252 static HbaToken *
00253 copy_hba_token(HbaToken *in)
00254 {
00255 HbaToken *out = make_hba_token(in->string, in->quoted);
00256
00257 return out;
00258 }
00259
00260
00261
00262
00263
00264
00265
00266
00267 static List *
00268 next_field_expand(const char *filename, char **lineptr)
00269 {
00270 char buf[MAX_TOKEN];
00271 bool trailing_comma;
00272 bool initial_quote;
00273 List *tokens = NIL;
00274
00275 do
00276 {
00277 if (!next_token(lineptr, buf, sizeof(buf), &initial_quote, &trailing_comma))
00278 break;
00279
00280
00281 if (!initial_quote && buf[0] == '@' && buf[1] != '\0')
00282 tokens = tokenize_inc_file(tokens, filename, buf + 1);
00283 else
00284 tokens = lappend(tokens, make_hba_token(buf, initial_quote));
00285 } while (trailing_comma);
00286
00287 return tokens;
00288 }
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299 static List *
00300 tokenize_inc_file(List *tokens,
00301 const char *outer_filename,
00302 const char *inc_filename)
00303 {
00304 char *inc_fullname;
00305 FILE *inc_file;
00306 List *inc_lines;
00307 List *inc_line_nums;
00308 ListCell *inc_line;
00309 MemoryContext linecxt;
00310
00311 if (is_absolute_path(inc_filename))
00312 {
00313
00314 inc_fullname = pstrdup(inc_filename);
00315 }
00316 else
00317 {
00318
00319 inc_fullname = (char *) palloc(strlen(outer_filename) + 1 +
00320 strlen(inc_filename) + 1);
00321 strcpy(inc_fullname, outer_filename);
00322 get_parent_directory(inc_fullname);
00323 join_path_components(inc_fullname, inc_fullname, inc_filename);
00324 canonicalize_path(inc_fullname);
00325 }
00326
00327 inc_file = AllocateFile(inc_fullname, "r");
00328 if (inc_file == NULL)
00329 {
00330 ereport(LOG,
00331 (errcode_for_file_access(),
00332 errmsg("could not open secondary authentication file \"@%s\" as \"%s\": %m",
00333 inc_filename, inc_fullname)));
00334 pfree(inc_fullname);
00335 return tokens;
00336 }
00337
00338
00339 linecxt = tokenize_file(inc_fullname, inc_file, &inc_lines, &inc_line_nums, NULL);
00340
00341 FreeFile(inc_file);
00342 pfree(inc_fullname);
00343
00344 foreach(inc_line, inc_lines)
00345 {
00346 List *inc_fields = lfirst(inc_line);
00347 ListCell *inc_field;
00348
00349 foreach(inc_field, inc_fields)
00350 {
00351 List *inc_tokens = lfirst(inc_field);
00352 ListCell *inc_token;
00353
00354 foreach(inc_token, inc_tokens)
00355 {
00356 HbaToken *token = lfirst(inc_token);
00357
00358 tokens = lappend(tokens, copy_hba_token(token));
00359 }
00360 }
00361 }
00362
00363 MemoryContextDelete(linecxt);
00364 return tokens;
00365 }
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379 static MemoryContext
00380 tokenize_file(const char *filename, FILE *file,
00381 List **lines, List **line_nums, List **raw_lines)
00382 {
00383 List *current_line = NIL;
00384 List *current_field = NIL;
00385 int line_number = 1;
00386 MemoryContext linecxt;
00387 MemoryContext oldcxt;
00388
00389 linecxt = AllocSetContextCreate(TopMemoryContext,
00390 "tokenize file cxt",
00391 ALLOCSET_DEFAULT_MINSIZE,
00392 ALLOCSET_DEFAULT_INITSIZE,
00393 ALLOCSET_DEFAULT_MAXSIZE);
00394 oldcxt = MemoryContextSwitchTo(linecxt);
00395
00396 *lines = *line_nums = NIL;
00397
00398 while (!feof(file) && !ferror(file))
00399 {
00400 char rawline[MAX_LINE];
00401 char *lineptr;
00402
00403 if (!fgets(rawline, sizeof(rawline), file))
00404 break;
00405 if (strlen(rawline) == MAX_LINE-1)
00406
00407 ereport(ERROR,
00408 (errcode(ERRCODE_CONFIG_FILE_ERROR),
00409 errmsg("authentication file line too long"),
00410 errcontext("line %d of configuration file \"%s\"",
00411 line_number, filename)));
00412
00413
00414 while (rawline[strlen(rawline)-1] == '\n' ||
00415 rawline[strlen(rawline)-1] == '\r')
00416 rawline[strlen(rawline)-1] = '\0';
00417
00418 lineptr = rawline;
00419 while (strlen(lineptr) > 0)
00420 {
00421 current_field = next_field_expand(filename, &lineptr);
00422
00423
00424 if (list_length(current_field) > 0)
00425 {
00426 if (current_line == NIL)
00427 {
00428
00429 current_line = lappend(current_line, current_field);
00430 *lines = lappend(*lines, current_line);
00431 *line_nums = lappend_int(*line_nums, line_number);
00432 if (raw_lines)
00433 *raw_lines = lappend(*raw_lines, pstrdup(rawline));
00434 }
00435 else
00436 {
00437
00438 current_line = lappend(current_line, current_field);
00439 }
00440 }
00441 }
00442
00443 current_line = NIL;
00444 line_number++;
00445 }
00446
00447 MemoryContextSwitchTo(oldcxt);
00448
00449 return linecxt;
00450 }
00451
00452
00453
00454
00455
00456
00457
00458
00459 static bool
00460 is_member(Oid userid, const char *role)
00461 {
00462 Oid roleid;
00463
00464 if (!OidIsValid(userid))
00465 return false;
00466
00467 roleid = get_role_oid(role, true);
00468
00469 if (!OidIsValid(roleid))
00470 return false;
00471
00472
00473
00474
00475
00476
00477 return is_member_of_role_nosuper(userid, roleid);
00478 }
00479
00480
00481
00482
00483 static bool
00484 check_role(const char *role, Oid roleid, List *tokens)
00485 {
00486 ListCell *cell;
00487 HbaToken *tok;
00488
00489 foreach(cell, tokens)
00490 {
00491 tok = lfirst(cell);
00492 if (!tok->quoted && tok->string[0] == '+')
00493 {
00494 if (is_member(roleid, tok->string + 1))
00495 return true;
00496 }
00497 else if (token_matches(tok, role) ||
00498 token_is_keyword(tok, "all"))
00499 return true;
00500 }
00501 return false;
00502 }
00503
00504
00505
00506
00507 static bool
00508 check_db(const char *dbname, const char *role, Oid roleid, List *tokens)
00509 {
00510 ListCell *cell;
00511 HbaToken *tok;
00512
00513 foreach(cell, tokens)
00514 {
00515 tok = lfirst(cell);
00516 if (am_walsender)
00517 {
00518
00519 if (token_is_keyword(tok, "replication"))
00520 return true;
00521 }
00522 else if (token_is_keyword(tok, "all"))
00523 return true;
00524 else if (token_is_keyword(tok, "sameuser"))
00525 {
00526 if (strcmp(dbname, role) == 0)
00527 return true;
00528 }
00529 else if (token_is_keyword(tok, "samegroup") ||
00530 token_is_keyword(tok, "samerole"))
00531 {
00532 if (is_member(roleid, dbname))
00533 return true;
00534 }
00535 else if (token_is_keyword(tok, "replication"))
00536 continue;
00537 else if (token_matches(tok, dbname))
00538 return true;
00539 }
00540 return false;
00541 }
00542
00543 static bool
00544 ipv4eq(struct sockaddr_in * a, struct sockaddr_in * b)
00545 {
00546 return (a->sin_addr.s_addr == b->sin_addr.s_addr);
00547 }
00548
00549 #ifdef HAVE_IPV6
00550
00551 static bool
00552 ipv6eq(struct sockaddr_in6 * a, struct sockaddr_in6 * b)
00553 {
00554 int i;
00555
00556 for (i = 0; i < 16; i++)
00557 if (a->sin6_addr.s6_addr[i] != b->sin6_addr.s6_addr[i])
00558 return false;
00559
00560 return true;
00561 }
00562 #endif
00563
00564
00565
00566
00567 static bool
00568 hostname_match(const char *pattern, const char *actual_hostname)
00569 {
00570 if (pattern[0] == '.')
00571 {
00572 size_t plen = strlen(pattern);
00573 size_t hlen = strlen(actual_hostname);
00574
00575 if (hlen < plen)
00576 return false;
00577
00578 return (pg_strcasecmp(pattern, actual_hostname + (hlen - plen)) == 0);
00579 }
00580 else
00581 return (pg_strcasecmp(pattern, actual_hostname) == 0);
00582 }
00583
00584
00585
00586
00587 static bool
00588 check_hostname(hbaPort *port, const char *hostname)
00589 {
00590 struct addrinfo *gai_result,
00591 *gai;
00592 int ret;
00593 bool found;
00594
00595
00596 if (!port->remote_hostname)
00597 {
00598 char remote_hostname[NI_MAXHOST];
00599
00600 if (pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
00601 remote_hostname, sizeof(remote_hostname),
00602 NULL, 0,
00603 0) != 0)
00604 return false;
00605
00606 port->remote_hostname = pstrdup(remote_hostname);
00607 }
00608
00609 if (!hostname_match(hostname, port->remote_hostname))
00610 return false;
00611
00612
00613
00614 if (port->remote_hostname_resolv == +1)
00615 return true;
00616 if (port->remote_hostname_resolv == -1)
00617 return false;
00618
00619 ret = getaddrinfo(port->remote_hostname, NULL, NULL, &gai_result);
00620 if (ret != 0)
00621 ereport(ERROR,
00622 (errmsg("could not translate host name \"%s\" to address: %s",
00623 port->remote_hostname, gai_strerror(ret))));
00624
00625 found = false;
00626 for (gai = gai_result; gai; gai = gai->ai_next)
00627 {
00628 if (gai->ai_addr->sa_family == port->raddr.addr.ss_family)
00629 {
00630 if (gai->ai_addr->sa_family == AF_INET)
00631 {
00632 if (ipv4eq((struct sockaddr_in *) gai->ai_addr,
00633 (struct sockaddr_in *) & port->raddr.addr))
00634 {
00635 found = true;
00636 break;
00637 }
00638 }
00639 #ifdef HAVE_IPV6
00640 else if (gai->ai_addr->sa_family == AF_INET6)
00641 {
00642 if (ipv6eq((struct sockaddr_in6 *) gai->ai_addr,
00643 (struct sockaddr_in6 *) & port->raddr.addr))
00644 {
00645 found = true;
00646 break;
00647 }
00648 }
00649 #endif
00650 }
00651 }
00652
00653 if (gai_result)
00654 freeaddrinfo(gai_result);
00655
00656 if (!found)
00657 elog(DEBUG2, "pg_hba.conf host name \"%s\" rejected because address resolution did not return a match with IP address of client",
00658 hostname);
00659
00660 port->remote_hostname_resolv = found ? +1 : -1;
00661
00662 return found;
00663 }
00664
00665
00666
00667
00668 static bool
00669 check_ip(SockAddr *raddr, struct sockaddr * addr, struct sockaddr * mask)
00670 {
00671 if (raddr->addr.ss_family == addr->sa_family)
00672 {
00673
00674 if (!pg_range_sockaddr(&raddr->addr,
00675 (struct sockaddr_storage *) addr,
00676 (struct sockaddr_storage *) mask))
00677 return false;
00678 }
00679 #ifdef HAVE_IPV6
00680 else if (addr->sa_family == AF_INET &&
00681 raddr->addr.ss_family == AF_INET6)
00682 {
00683
00684
00685
00686
00687
00688 struct sockaddr_storage addrcopy,
00689 maskcopy;
00690
00691 memcpy(&addrcopy, &addr, sizeof(addrcopy));
00692 memcpy(&maskcopy, &mask, sizeof(maskcopy));
00693 pg_promote_v4_to_v6_addr(&addrcopy);
00694 pg_promote_v4_to_v6_mask(&maskcopy);
00695
00696 if (!pg_range_sockaddr(&raddr->addr, &addrcopy, &maskcopy))
00697 return false;
00698 }
00699 #endif
00700 else
00701 {
00702
00703 return false;
00704 }
00705
00706 return true;
00707 }
00708
00709
00710
00711
00712 static void
00713 check_network_callback(struct sockaddr * addr, struct sockaddr * netmask,
00714 void *cb_data)
00715 {
00716 check_network_data *cn = (check_network_data *) cb_data;
00717 struct sockaddr_storage mask;
00718
00719
00720 if (cn->result)
00721 return;
00722
00723 if (cn->method == ipCmpSameHost)
00724 {
00725
00726 pg_sockaddr_cidr_mask(&mask, NULL, addr->sa_family);
00727 cn->result = check_ip(cn->raddr, addr, (struct sockaddr *) & mask);
00728 }
00729 else
00730 {
00731
00732 cn->result = check_ip(cn->raddr, addr, netmask);
00733 }
00734 }
00735
00736
00737
00738
00739 static bool
00740 check_same_host_or_net(SockAddr *raddr, IPCompareMethod method)
00741 {
00742 check_network_data cn;
00743
00744 cn.method = method;
00745 cn.raddr = raddr;
00746 cn.result = false;
00747
00748 errno = 0;
00749 if (pg_foreach_ifaddr(check_network_callback, &cn) < 0)
00750 {
00751 elog(LOG, "error enumerating network interfaces: %m");
00752 return false;
00753 }
00754
00755 return cn.result;
00756 }
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769 #define INVALID_AUTH_OPTION(optname, validmethods) do {\
00770 ereport(LOG, \
00771 (errcode(ERRCODE_CONFIG_FILE_ERROR), \
00772 \
00773 errmsg("authentication option \"%s\" is only valid for authentication methods %s", \
00774 optname, _(validmethods)), \
00775 errcontext("line %d of configuration file \"%s\"", \
00776 line_num, HbaFileName))); \
00777 return false; \
00778 } while (0);
00779
00780 #define REQUIRE_AUTH_OPTION(methodval, optname, validmethods) do {\
00781 if (hbaline->auth_method != methodval) \
00782 INVALID_AUTH_OPTION(optname, validmethods); \
00783 } while (0);
00784
00785 #define MANDATORY_AUTH_ARG(argvar, argname, authname) do {\
00786 if (argvar == NULL) {\
00787 ereport(LOG, \
00788 (errcode(ERRCODE_CONFIG_FILE_ERROR), \
00789 errmsg("authentication method \"%s\" requires argument \"%s\" to be set", \
00790 authname, argname), \
00791 errcontext("line %d of configuration file \"%s\"", \
00792 line_num, HbaFileName))); \
00793 return NULL; \
00794 } \
00795 } while (0);
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806 #define IDENT_FIELD_ABSENT(field) do {\
00807 if (!field) { \
00808 ereport(LOG, \
00809 (errcode(ERRCODE_CONFIG_FILE_ERROR), \
00810 errmsg("missing entry in file \"%s\" at end of line %d", \
00811 IdentFileName, line_number))); \
00812 return NULL; \
00813 } \
00814 } while (0);
00815
00816 #define IDENT_MULTI_VALUE(tokens) do {\
00817 if (tokens->length > 1) { \
00818 ereport(LOG, \
00819 (errcode(ERRCODE_CONFIG_FILE_ERROR), \
00820 errmsg("multiple values in ident field"), \
00821 errcontext("line %d of configuration file \"%s\"", \
00822 line_number, IdentFileName))); \
00823 return NULL; \
00824 } \
00825 } while (0);
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839 static HbaLine *
00840 parse_hba_line(List *line, int line_num, char *raw_line)
00841 {
00842 char *str;
00843 struct addrinfo *gai_result;
00844 struct addrinfo hints;
00845 int ret;
00846 char *cidr_slash;
00847 char *unsupauth;
00848 ListCell *field;
00849 List *tokens;
00850 ListCell *tokencell;
00851 HbaToken *token;
00852 HbaLine *parsedline;
00853
00854 parsedline = palloc0(sizeof(HbaLine));
00855 parsedline->linenumber = line_num;
00856 parsedline->rawline = pstrdup(raw_line);
00857
00858
00859 field = list_head(line);
00860 tokens = lfirst(field);
00861 if (tokens->length > 1)
00862 {
00863 ereport(LOG,
00864 (errcode(ERRCODE_CONFIG_FILE_ERROR),
00865 errmsg("multiple values specified for connection type"),
00866 errhint("Specify exactly one connection type per line."),
00867 errcontext("line %d of configuration file \"%s\"",
00868 line_num, HbaFileName)));
00869 return NULL;
00870 }
00871 token = linitial(tokens);
00872 if (strcmp(token->string, "local") == 0)
00873 {
00874 #ifdef HAVE_UNIX_SOCKETS
00875 parsedline->conntype = ctLocal;
00876 #else
00877 ereport(LOG,
00878 (errcode(ERRCODE_CONFIG_FILE_ERROR),
00879 errmsg("local connections are not supported by this build"),
00880 errcontext("line %d of configuration file \"%s\"",
00881 line_num, HbaFileName)));
00882 return NULL;
00883 #endif
00884 }
00885 else if (strcmp(token->string, "host") == 0 ||
00886 strcmp(token->string, "hostssl") == 0 ||
00887 strcmp(token->string, "hostnossl") == 0)
00888 {
00889
00890 if (token->string[4] == 's')
00891 {
00892
00893 #ifdef USE_SSL
00894 if (EnableSSL)
00895 parsedline->conntype = ctHostSSL;
00896 else
00897 {
00898 ereport(LOG,
00899 (errcode(ERRCODE_CONFIG_FILE_ERROR),
00900 errmsg("hostssl requires SSL to be turned on"),
00901 errhint("Set ssl = on in postgresql.conf."),
00902 errcontext("line %d of configuration file \"%s\"",
00903 line_num, HbaFileName)));
00904 return NULL;
00905 }
00906 #else
00907 ereport(LOG,
00908 (errcode(ERRCODE_CONFIG_FILE_ERROR),
00909 errmsg("hostssl is not supported by this build"),
00910 errhint("Compile with --with-openssl to use SSL connections."),
00911 errcontext("line %d of configuration file \"%s\"",
00912 line_num, HbaFileName)));
00913 return NULL;
00914 #endif
00915 }
00916 #ifdef USE_SSL
00917 else if (token->string[4] == 'n')
00918 {
00919 parsedline->conntype = ctHostNoSSL;
00920 }
00921 #endif
00922 else
00923 {
00924
00925 parsedline->conntype = ctHost;
00926 }
00927 }
00928 else
00929 {
00930 ereport(LOG,
00931 (errcode(ERRCODE_CONFIG_FILE_ERROR),
00932 errmsg("invalid connection type \"%s\"",
00933 token->string),
00934 errcontext("line %d of configuration file \"%s\"",
00935 line_num, HbaFileName)));
00936 return NULL;
00937 }
00938
00939
00940 field = lnext(field);
00941 if (!field)
00942 {
00943 ereport(LOG,
00944 (errcode(ERRCODE_CONFIG_FILE_ERROR),
00945 errmsg("end-of-line before database specification"),
00946 errcontext("line %d of configuration file \"%s\"",
00947 line_num, HbaFileName)));
00948 return NULL;
00949 }
00950 parsedline->databases = NIL;
00951 tokens = lfirst(field);
00952 foreach(tokencell, tokens)
00953 {
00954 parsedline->databases = lappend(parsedline->databases,
00955 copy_hba_token(lfirst(tokencell)));
00956 }
00957
00958
00959 field = lnext(field);
00960 if (!field)
00961 {
00962 ereport(LOG,
00963 (errcode(ERRCODE_CONFIG_FILE_ERROR),
00964 errmsg("end-of-line before role specification"),
00965 errcontext("line %d of configuration file \"%s\"",
00966 line_num, HbaFileName)));
00967 return NULL;
00968 }
00969 parsedline->roles = NIL;
00970 tokens = lfirst(field);
00971 foreach(tokencell, tokens)
00972 {
00973 parsedline->roles = lappend(parsedline->roles,
00974 copy_hba_token(lfirst(tokencell)));
00975 }
00976
00977 if (parsedline->conntype != ctLocal)
00978 {
00979
00980 field = lnext(field);
00981 if (!field)
00982 {
00983 ereport(LOG,
00984 (errcode(ERRCODE_CONFIG_FILE_ERROR),
00985 errmsg("end-of-line before IP address specification"),
00986 errcontext("line %d of configuration file \"%s\"",
00987 line_num, HbaFileName)));
00988 return NULL;
00989 }
00990 tokens = lfirst(field);
00991 if (tokens->length > 1)
00992 {
00993 ereport(LOG,
00994 (errcode(ERRCODE_CONFIG_FILE_ERROR),
00995 errmsg("multiple values specified for host address"),
00996 errhint("Specify one address range per line."),
00997 errcontext("line %d of configuration file \"%s\"",
00998 line_num, HbaFileName)));
00999 return NULL;
01000 }
01001 token = linitial(tokens);
01002
01003 if (token_is_keyword(token, "all"))
01004 {
01005 parsedline->ip_cmp_method = ipCmpAll;
01006 }
01007 else if (token_is_keyword(token, "samehost"))
01008 {
01009
01010 parsedline->ip_cmp_method = ipCmpSameHost;
01011 }
01012 else if (token_is_keyword(token, "samenet"))
01013 {
01014
01015 parsedline->ip_cmp_method = ipCmpSameNet;
01016 }
01017 else
01018 {
01019
01020 parsedline->ip_cmp_method = ipCmpMask;
01021
01022
01023 str = pstrdup(token->string);
01024
01025
01026 cidr_slash = strchr(str, '/');
01027 if (cidr_slash)
01028 *cidr_slash = '\0';
01029
01030
01031 hints.ai_flags = AI_NUMERICHOST;
01032 hints.ai_family = PF_UNSPEC;
01033 hints.ai_socktype = 0;
01034 hints.ai_protocol = 0;
01035 hints.ai_addrlen = 0;
01036 hints.ai_canonname = NULL;
01037 hints.ai_addr = NULL;
01038 hints.ai_next = NULL;
01039
01040 ret = pg_getaddrinfo_all(str, NULL, &hints, &gai_result);
01041 if (ret == 0 && gai_result)
01042 memcpy(&parsedline->addr, gai_result->ai_addr,
01043 gai_result->ai_addrlen);
01044 else if (ret == EAI_NONAME)
01045 parsedline->hostname = str;
01046 else
01047 {
01048 ereport(LOG,
01049 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01050 errmsg("invalid IP address \"%s\": %s",
01051 str, gai_strerror(ret)),
01052 errcontext("line %d of configuration file \"%s\"",
01053 line_num, HbaFileName)));
01054 if (gai_result)
01055 pg_freeaddrinfo_all(hints.ai_family, gai_result);
01056 return NULL;
01057 }
01058
01059 pg_freeaddrinfo_all(hints.ai_family, gai_result);
01060
01061
01062 if (cidr_slash)
01063 {
01064 if (parsedline->hostname)
01065 {
01066 ereport(LOG,
01067 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01068 errmsg("specifying both host name and CIDR mask is invalid: \"%s\"",
01069 token->string),
01070 errcontext("line %d of configuration file \"%s\"",
01071 line_num, HbaFileName)));
01072 return NULL;
01073 }
01074
01075 if (pg_sockaddr_cidr_mask(&parsedline->mask, cidr_slash + 1,
01076 parsedline->addr.ss_family) < 0)
01077 {
01078 ereport(LOG,
01079 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01080 errmsg("invalid CIDR mask in address \"%s\"",
01081 token->string),
01082 errcontext("line %d of configuration file \"%s\"",
01083 line_num, HbaFileName)));
01084 return NULL;
01085 }
01086 pfree(str);
01087 }
01088 else if (!parsedline->hostname)
01089 {
01090
01091 pfree(str);
01092 field = lnext(field);
01093 if (!field)
01094 {
01095 ereport(LOG,
01096 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01097 errmsg("end-of-line before netmask specification"),
01098 errhint("Specify an address range in CIDR notation, or provide a separate netmask."),
01099 errcontext("line %d of configuration file \"%s\"",
01100 line_num, HbaFileName)));
01101 return NULL;
01102 }
01103 tokens = lfirst(field);
01104 if (tokens->length > 1)
01105 {
01106 ereport(LOG,
01107 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01108 errmsg("multiple values specified for netmask"),
01109 errcontext("line %d of configuration file \"%s\"",
01110 line_num, HbaFileName)));
01111 return NULL;
01112 }
01113 token = linitial(tokens);
01114
01115 ret = pg_getaddrinfo_all(token->string, NULL,
01116 &hints, &gai_result);
01117 if (ret || !gai_result)
01118 {
01119 ereport(LOG,
01120 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01121 errmsg("invalid IP mask \"%s\": %s",
01122 token->string, gai_strerror(ret)),
01123 errcontext("line %d of configuration file \"%s\"",
01124 line_num, HbaFileName)));
01125 if (gai_result)
01126 pg_freeaddrinfo_all(hints.ai_family, gai_result);
01127 return NULL;
01128 }
01129
01130 memcpy(&parsedline->mask, gai_result->ai_addr,
01131 gai_result->ai_addrlen);
01132 pg_freeaddrinfo_all(hints.ai_family, gai_result);
01133
01134 if (parsedline->addr.ss_family != parsedline->mask.ss_family)
01135 {
01136 ereport(LOG,
01137 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01138 errmsg("IP address and mask do not match"),
01139 errcontext("line %d of configuration file \"%s\"",
01140 line_num, HbaFileName)));
01141 return NULL;
01142 }
01143 }
01144 }
01145 }
01146
01147
01148 field = lnext(field);
01149 if (!field)
01150 {
01151 ereport(LOG,
01152 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01153 errmsg("end-of-line before authentication method"),
01154 errcontext("line %d of configuration file \"%s\"",
01155 line_num, HbaFileName)));
01156 return NULL;
01157 }
01158 tokens = lfirst(field);
01159 if (tokens->length > 1)
01160 {
01161 ereport(LOG,
01162 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01163 errmsg("multiple values specified for authentication type"),
01164 errhint("Specify exactly one authentication type per line."),
01165 errcontext("line %d of configuration file \"%s\"",
01166 line_num, HbaFileName)));
01167 return NULL;
01168 }
01169 token = linitial(tokens);
01170
01171 unsupauth = NULL;
01172 if (strcmp(token->string, "trust") == 0)
01173 parsedline->auth_method = uaTrust;
01174 else if (strcmp(token->string, "ident") == 0)
01175 parsedline->auth_method = uaIdent;
01176 else if (strcmp(token->string, "peer") == 0)
01177 parsedline->auth_method = uaPeer;
01178 else if (strcmp(token->string, "password") == 0)
01179 parsedline->auth_method = uaPassword;
01180 else if (strcmp(token->string, "krb5") == 0)
01181 #ifdef KRB5
01182 parsedline->auth_method = uaKrb5;
01183 #else
01184 unsupauth = "krb5";
01185 #endif
01186 else if (strcmp(token->string, "gss") == 0)
01187 #ifdef ENABLE_GSS
01188 parsedline->auth_method = uaGSS;
01189 #else
01190 unsupauth = "gss";
01191 #endif
01192 else if (strcmp(token->string, "sspi") == 0)
01193 #ifdef ENABLE_SSPI
01194 parsedline->auth_method = uaSSPI;
01195 #else
01196 unsupauth = "sspi";
01197 #endif
01198 else if (strcmp(token->string, "reject") == 0)
01199 parsedline->auth_method = uaReject;
01200 else if (strcmp(token->string, "md5") == 0)
01201 {
01202 if (Db_user_namespace)
01203 {
01204 ereport(LOG,
01205 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01206 errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled"),
01207 errcontext("line %d of configuration file \"%s\"",
01208 line_num, HbaFileName)));
01209 return NULL;
01210 }
01211 parsedline->auth_method = uaMD5;
01212 }
01213 else if (strcmp(token->string, "pam") == 0)
01214 #ifdef USE_PAM
01215 parsedline->auth_method = uaPAM;
01216 #else
01217 unsupauth = "pam";
01218 #endif
01219 else if (strcmp(token->string, "ldap") == 0)
01220 #ifdef USE_LDAP
01221 parsedline->auth_method = uaLDAP;
01222 #else
01223 unsupauth = "ldap";
01224 #endif
01225 else if (strcmp(token->string, "cert") == 0)
01226 #ifdef USE_SSL
01227 parsedline->auth_method = uaCert;
01228 #else
01229 unsupauth = "cert";
01230 #endif
01231 else if (strcmp(token->string, "radius") == 0)
01232 parsedline->auth_method = uaRADIUS;
01233 else
01234 {
01235 ereport(LOG,
01236 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01237 errmsg("invalid authentication method \"%s\"",
01238 token->string),
01239 errcontext("line %d of configuration file \"%s\"",
01240 line_num, HbaFileName)));
01241 return NULL;
01242 }
01243
01244 if (unsupauth)
01245 {
01246 ereport(LOG,
01247 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01248 errmsg("invalid authentication method \"%s\": not supported by this build",
01249 token->string),
01250 errcontext("line %d of configuration file \"%s\"",
01251 line_num, HbaFileName)));
01252 return NULL;
01253 }
01254
01255
01256
01257
01258
01259 if (parsedline->conntype == ctLocal &&
01260 parsedline->auth_method == uaIdent)
01261 parsedline->auth_method = uaPeer;
01262
01263
01264 if (parsedline->conntype == ctLocal &&
01265 parsedline->auth_method == uaKrb5)
01266 {
01267 ereport(LOG,
01268 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01269 errmsg("krb5 authentication is not supported on local sockets"),
01270 errcontext("line %d of configuration file \"%s\"",
01271 line_num, HbaFileName)));
01272 return NULL;
01273 }
01274
01275 if (parsedline->conntype == ctLocal &&
01276 parsedline->auth_method == uaGSS)
01277 {
01278 ereport(LOG,
01279 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01280 errmsg("gssapi authentication is not supported on local sockets"),
01281 errcontext("line %d of configuration file \"%s\"",
01282 line_num, HbaFileName)));
01283 return NULL;
01284 }
01285
01286 if (parsedline->conntype != ctLocal &&
01287 parsedline->auth_method == uaPeer)
01288 {
01289 ereport(LOG,
01290 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01291 errmsg("peer authentication is only supported on local sockets"),
01292 errcontext("line %d of configuration file \"%s\"",
01293 line_num, HbaFileName)));
01294 return NULL;
01295 }
01296
01297
01298
01299
01300
01301
01302
01303 if (parsedline->conntype != ctHostSSL &&
01304 parsedline->auth_method == uaCert)
01305 {
01306 ereport(LOG,
01307 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01308 errmsg("cert authentication is only supported on hostssl connections"),
01309 errcontext("line %d of configuration file \"%s\"",
01310 line_num, HbaFileName)));
01311 return NULL;
01312 }
01313
01314
01315 while ((field = lnext(field)) != NULL)
01316 {
01317 tokens = lfirst(field);
01318 foreach(tokencell, tokens)
01319 {
01320 char *val;
01321
01322 token = lfirst(tokencell);
01323
01324 str = pstrdup(token->string);
01325 val = strchr(str, '=');
01326 if (val == NULL)
01327 {
01328
01329
01330
01331 ereport(LOG,
01332 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01333 errmsg("authentication option not in name=value format: %s", token->string),
01334 errcontext("line %d of configuration file \"%s\"",
01335 line_num, HbaFileName)));
01336 return NULL;
01337 }
01338
01339 *val++ = '\0';
01340 if (!parse_hba_auth_opt(str, val, parsedline, line_num))
01341
01342 return NULL;
01343 pfree(str);
01344 }
01345 }
01346
01347
01348
01349
01350
01351 if (parsedline->auth_method == uaLDAP)
01352 {
01353 MANDATORY_AUTH_ARG(parsedline->ldapserver, "ldapserver", "ldap");
01354
01355
01356
01357
01358
01359
01360
01361 if (parsedline->ldapprefix || parsedline->ldapsuffix)
01362 {
01363 if (parsedline->ldapbasedn ||
01364 parsedline->ldapbinddn ||
01365 parsedline->ldapbindpasswd ||
01366 parsedline->ldapsearchattribute)
01367 {
01368 ereport(LOG,
01369 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01370 errmsg("cannot use ldapbasedn, ldapbinddn, ldapbindpasswd, ldapsearchattribute, or ldapurl together with ldapprefix"),
01371 errcontext("line %d of configuration file \"%s\"",
01372 line_num, HbaFileName)));
01373 return NULL;
01374 }
01375 }
01376 else if (!parsedline->ldapbasedn)
01377 {
01378 ereport(LOG,
01379 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01380 errmsg("authentication method \"ldap\" requires argument \"ldapbasedn\", \"ldapprefix\", or \"ldapsuffix\" to be set"),
01381 errcontext("line %d of configuration file \"%s\"",
01382 line_num, HbaFileName)));
01383 return NULL;
01384 }
01385 }
01386
01387 if (parsedline->auth_method == uaRADIUS)
01388 {
01389 MANDATORY_AUTH_ARG(parsedline->radiusserver, "radiusserver", "radius");
01390 MANDATORY_AUTH_ARG(parsedline->radiussecret, "radiussecret", "radius");
01391 }
01392
01393
01394
01395
01396 if (parsedline->auth_method == uaCert)
01397 {
01398 parsedline->clientcert = true;
01399 }
01400
01401 return parsedline;
01402 }
01403
01404
01405
01406
01407
01408
01409 static bool
01410 parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num)
01411 {
01412 #ifdef USE_LDAP
01413 hbaline->ldapscope = LDAP_SCOPE_SUBTREE;
01414 #endif
01415
01416 if (strcmp(name, "map") == 0)
01417 {
01418 if (hbaline->auth_method != uaIdent &&
01419 hbaline->auth_method != uaPeer &&
01420 hbaline->auth_method != uaKrb5 &&
01421 hbaline->auth_method != uaGSS &&
01422 hbaline->auth_method != uaSSPI &&
01423 hbaline->auth_method != uaCert)
01424 INVALID_AUTH_OPTION("map", gettext_noop("ident, peer, krb5, gssapi, sspi, and cert"));
01425 hbaline->usermap = pstrdup(val);
01426 }
01427 else if (strcmp(name, "clientcert") == 0)
01428 {
01429
01430
01431
01432
01433 if (hbaline->conntype != ctHostSSL)
01434 {
01435 ereport(LOG,
01436 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01437 errmsg("clientcert can only be configured for \"hostssl\" rows"),
01438 errcontext("line %d of configuration file \"%s\"",
01439 line_num, HbaFileName)));
01440 return false;
01441 }
01442 if (strcmp(val, "1") == 0)
01443 {
01444 if (!secure_loaded_verify_locations())
01445 {
01446 ereport(LOG,
01447 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01448 errmsg("client certificates can only be checked if a root certificate store is available"),
01449 errhint("Make sure the configuration parameter \"ssl_ca_file\" is set."),
01450 errcontext("line %d of configuration file \"%s\"",
01451 line_num, HbaFileName)));
01452 return false;
01453 }
01454 hbaline->clientcert = true;
01455 }
01456 else
01457 {
01458 if (hbaline->auth_method == uaCert)
01459 {
01460 ereport(LOG,
01461 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01462 errmsg("clientcert can not be set to 0 when using \"cert\" authentication"),
01463 errcontext("line %d of configuration file \"%s\"",
01464 line_num, HbaFileName)));
01465 return false;
01466 }
01467 hbaline->clientcert = false;
01468 }
01469 }
01470 else if (strcmp(name, "pamservice") == 0)
01471 {
01472 REQUIRE_AUTH_OPTION(uaPAM, "pamservice", "pam");
01473 hbaline->pamservice = pstrdup(val);
01474 }
01475 else if (strcmp(name, "ldapurl") == 0)
01476 {
01477 #ifdef LDAP_API_FEATURE_X_OPENLDAP
01478 LDAPURLDesc *urldata;
01479 int rc;
01480 #endif
01481
01482 REQUIRE_AUTH_OPTION(uaLDAP, "ldapurl", "ldap");
01483 #ifdef LDAP_API_FEATURE_X_OPENLDAP
01484 rc = ldap_url_parse(val, &urldata);
01485 if (rc != LDAP_SUCCESS)
01486 {
01487 ereport(LOG,
01488 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01489 errmsg("could not parse LDAP URL \"%s\": %s", val, ldap_err2string(rc))));
01490 return false;
01491 }
01492
01493 if (strcmp(urldata->lud_scheme, "ldap") != 0)
01494 {
01495 ereport(LOG,
01496 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01497 errmsg("unsupported LDAP URL scheme: %s", urldata->lud_scheme)));
01498 ldap_free_urldesc(urldata);
01499 return false;
01500 }
01501
01502 hbaline->ldapserver = pstrdup(urldata->lud_host);
01503 hbaline->ldapport = urldata->lud_port;
01504 hbaline->ldapbasedn = pstrdup(urldata->lud_dn);
01505
01506 if (urldata->lud_attrs)
01507 hbaline->ldapsearchattribute = pstrdup(urldata->lud_attrs[0]);
01508 hbaline->ldapscope = urldata->lud_scope;
01509 if (urldata->lud_filter)
01510 {
01511 ereport(LOG,
01512 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01513 errmsg("filters not supported in LDAP URLs")));
01514 ldap_free_urldesc(urldata);
01515 return false;
01516 }
01517 ldap_free_urldesc(urldata);
01518 #else
01519 ereport(LOG,
01520 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01521 errmsg("LDAP URLs not supported on this platform")));
01522 #endif
01523 }
01524 else if (strcmp(name, "ldaptls") == 0)
01525 {
01526 REQUIRE_AUTH_OPTION(uaLDAP, "ldaptls", "ldap");
01527 if (strcmp(val, "1") == 0)
01528 hbaline->ldaptls = true;
01529 else
01530 hbaline->ldaptls = false;
01531 }
01532 else if (strcmp(name, "ldapserver") == 0)
01533 {
01534 REQUIRE_AUTH_OPTION(uaLDAP, "ldapserver", "ldap");
01535 hbaline->ldapserver = pstrdup(val);
01536 }
01537 else if (strcmp(name, "ldapport") == 0)
01538 {
01539 REQUIRE_AUTH_OPTION(uaLDAP, "ldapport", "ldap");
01540 hbaline->ldapport = atoi(val);
01541 if (hbaline->ldapport == 0)
01542 {
01543 ereport(LOG,
01544 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01545 errmsg("invalid LDAP port number: \"%s\"", val),
01546 errcontext("line %d of configuration file \"%s\"",
01547 line_num, HbaFileName)));
01548 return false;
01549 }
01550 }
01551 else if (strcmp(name, "ldapbinddn") == 0)
01552 {
01553 REQUIRE_AUTH_OPTION(uaLDAP, "ldapbinddn", "ldap");
01554 hbaline->ldapbinddn = pstrdup(val);
01555 }
01556 else if (strcmp(name, "ldapbindpasswd") == 0)
01557 {
01558 REQUIRE_AUTH_OPTION(uaLDAP, "ldapbindpasswd", "ldap");
01559 hbaline->ldapbindpasswd = pstrdup(val);
01560 }
01561 else if (strcmp(name, "ldapsearchattribute") == 0)
01562 {
01563 REQUIRE_AUTH_OPTION(uaLDAP, "ldapsearchattribute", "ldap");
01564 hbaline->ldapsearchattribute = pstrdup(val);
01565 }
01566 else if (strcmp(name, "ldapbasedn") == 0)
01567 {
01568 REQUIRE_AUTH_OPTION(uaLDAP, "ldapbasedn", "ldap");
01569 hbaline->ldapbasedn = pstrdup(val);
01570 }
01571 else if (strcmp(name, "ldapprefix") == 0)
01572 {
01573 REQUIRE_AUTH_OPTION(uaLDAP, "ldapprefix", "ldap");
01574 hbaline->ldapprefix = pstrdup(val);
01575 }
01576 else if (strcmp(name, "ldapsuffix") == 0)
01577 {
01578 REQUIRE_AUTH_OPTION(uaLDAP, "ldapsuffix", "ldap");
01579 hbaline->ldapsuffix = pstrdup(val);
01580 }
01581 else if (strcmp(name, "krb_server_hostname") == 0)
01582 {
01583 REQUIRE_AUTH_OPTION(uaKrb5, "krb_server_hostname", "krb5");
01584 hbaline->krb_server_hostname = pstrdup(val);
01585 }
01586 else if (strcmp(name, "krb_realm") == 0)
01587 {
01588 if (hbaline->auth_method != uaKrb5 &&
01589 hbaline->auth_method != uaGSS &&
01590 hbaline->auth_method != uaSSPI)
01591 INVALID_AUTH_OPTION("krb_realm", gettext_noop("krb5, gssapi, and sspi"));
01592 hbaline->krb_realm = pstrdup(val);
01593 }
01594 else if (strcmp(name, "include_realm") == 0)
01595 {
01596 if (hbaline->auth_method != uaKrb5 &&
01597 hbaline->auth_method != uaGSS &&
01598 hbaline->auth_method != uaSSPI)
01599 INVALID_AUTH_OPTION("include_realm", gettext_noop("krb5, gssapi, and sspi"));
01600 if (strcmp(val, "1") == 0)
01601 hbaline->include_realm = true;
01602 else
01603 hbaline->include_realm = false;
01604 }
01605 else if (strcmp(name, "radiusserver") == 0)
01606 {
01607 struct addrinfo *gai_result;
01608 struct addrinfo hints;
01609 int ret;
01610
01611 REQUIRE_AUTH_OPTION(uaRADIUS, "radiusserver", "radius");
01612
01613 MemSet(&hints, 0, sizeof(hints));
01614 hints.ai_socktype = SOCK_DGRAM;
01615 hints.ai_family = AF_UNSPEC;
01616
01617 ret = pg_getaddrinfo_all(val, NULL, &hints, &gai_result);
01618 if (ret || !gai_result)
01619 {
01620 ereport(LOG,
01621 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01622 errmsg("could not translate RADIUS server name \"%s\" to address: %s",
01623 val, gai_strerror(ret)),
01624 errcontext("line %d of configuration file \"%s\"",
01625 line_num, HbaFileName)));
01626 if (gai_result)
01627 pg_freeaddrinfo_all(hints.ai_family, gai_result);
01628 return false;
01629 }
01630 pg_freeaddrinfo_all(hints.ai_family, gai_result);
01631 hbaline->radiusserver = pstrdup(val);
01632 }
01633 else if (strcmp(name, "radiusport") == 0)
01634 {
01635 REQUIRE_AUTH_OPTION(uaRADIUS, "radiusport", "radius");
01636 hbaline->radiusport = atoi(val);
01637 if (hbaline->radiusport == 0)
01638 {
01639 ereport(LOG,
01640 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01641 errmsg("invalid RADIUS port number: \"%s\"", val),
01642 errcontext("line %d of configuration file \"%s\"",
01643 line_num, HbaFileName)));
01644 return false;
01645 }
01646 }
01647 else if (strcmp(name, "radiussecret") == 0)
01648 {
01649 REQUIRE_AUTH_OPTION(uaRADIUS, "radiussecret", "radius");
01650 hbaline->radiussecret = pstrdup(val);
01651 }
01652 else if (strcmp(name, "radiusidentifier") == 0)
01653 {
01654 REQUIRE_AUTH_OPTION(uaRADIUS, "radiusidentifier", "radius");
01655 hbaline->radiusidentifier = pstrdup(val);
01656 }
01657 else
01658 {
01659 ereport(LOG,
01660 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01661 errmsg("unrecognized authentication option name: \"%s\"",
01662 name),
01663 errcontext("line %d of configuration file \"%s\"",
01664 line_num, HbaFileName)));
01665 return false;
01666 }
01667 return true;
01668 }
01669
01670
01671
01672
01673
01674 static void
01675 check_hba(hbaPort *port)
01676 {
01677 Oid roleid;
01678 ListCell *line;
01679 HbaLine *hba;
01680
01681
01682 roleid = get_role_oid(port->user_name, true);
01683
01684 foreach(line, parsed_hba_lines)
01685 {
01686 hba = (HbaLine *) lfirst(line);
01687
01688
01689 if (hba->conntype == ctLocal)
01690 {
01691 if (!IS_AF_UNIX(port->raddr.addr.ss_family))
01692 continue;
01693 }
01694 else
01695 {
01696 if (IS_AF_UNIX(port->raddr.addr.ss_family))
01697 continue;
01698
01699
01700 #ifdef USE_SSL
01701 if (port->ssl)
01702 {
01703
01704 if (hba->conntype == ctHostNoSSL)
01705 continue;
01706 }
01707 else
01708 {
01709
01710 if (hba->conntype == ctHostSSL)
01711 continue;
01712 }
01713 #else
01714
01715 if (hba->conntype == ctHostSSL)
01716 continue;
01717 #endif
01718
01719
01720 switch (hba->ip_cmp_method)
01721 {
01722 case ipCmpMask:
01723 if (hba->hostname)
01724 {
01725 if (!check_hostname(port,
01726 hba->hostname))
01727 continue;
01728 }
01729 else
01730 {
01731 if (!check_ip(&port->raddr,
01732 (struct sockaddr *) & hba->addr,
01733 (struct sockaddr *) & hba->mask))
01734 continue;
01735 }
01736 break;
01737 case ipCmpAll:
01738 break;
01739 case ipCmpSameHost:
01740 case ipCmpSameNet:
01741 if (!check_same_host_or_net(&port->raddr,
01742 hba->ip_cmp_method))
01743 continue;
01744 break;
01745 default:
01746
01747 continue;
01748 }
01749 }
01750
01751
01752 if (!check_db(port->database_name, port->user_name, roleid,
01753 hba->databases))
01754 continue;
01755
01756 if (!check_role(port->user_name, roleid, hba->roles))
01757 continue;
01758
01759
01760 port->hba = hba;
01761 return;
01762 }
01763
01764
01765 hba = palloc0(sizeof(HbaLine));
01766 hba->auth_method = uaImplicitReject;
01767 port->hba = hba;
01768 }
01769
01770
01771
01772
01773
01774
01775
01776
01777
01778
01779
01780
01781 bool
01782 load_hba(void)
01783 {
01784 FILE *file;
01785 List *hba_lines = NIL;
01786 List *hba_line_nums = NIL;
01787 List *hba_raw_lines = NIL;
01788 ListCell *line,
01789 *line_num,
01790 *raw_line;
01791 List *new_parsed_lines = NIL;
01792 bool ok = true;
01793 MemoryContext linecxt;
01794 MemoryContext oldcxt;
01795 MemoryContext hbacxt;
01796
01797 file = AllocateFile(HbaFileName, "r");
01798 if (file == NULL)
01799 {
01800 ereport(LOG,
01801 (errcode_for_file_access(),
01802 errmsg("could not open configuration file \"%s\": %m",
01803 HbaFileName)));
01804 return false;
01805 }
01806
01807 linecxt = tokenize_file(HbaFileName, file, &hba_lines, &hba_line_nums, &hba_raw_lines);
01808 FreeFile(file);
01809
01810
01811 hbacxt = AllocSetContextCreate(TopMemoryContext,
01812 "hba parser context",
01813 ALLOCSET_DEFAULT_MINSIZE,
01814 ALLOCSET_DEFAULT_MINSIZE,
01815 ALLOCSET_DEFAULT_MAXSIZE);
01816 oldcxt = MemoryContextSwitchTo(hbacxt);
01817 forthree(line, hba_lines, line_num, hba_line_nums, raw_line, hba_raw_lines)
01818 {
01819 HbaLine *newline;
01820
01821 if ((newline = parse_hba_line(lfirst(line), lfirst_int(line_num), lfirst(raw_line))) == NULL)
01822 {
01823
01824
01825
01826
01827
01828 MemoryContextReset(hbacxt);
01829 new_parsed_lines = NIL;
01830 ok = false;
01831
01832
01833
01834
01835
01836
01837 continue;
01838 }
01839
01840 new_parsed_lines = lappend(new_parsed_lines, newline);
01841 }
01842
01843
01844
01845
01846
01847
01848 if (ok && new_parsed_lines == NIL)
01849 {
01850 ereport(LOG,
01851 (errcode(ERRCODE_CONFIG_FILE_ERROR),
01852 errmsg("configuration file \"%s\" contains no entries",
01853 HbaFileName)));
01854 ok = false;
01855 }
01856
01857
01858 MemoryContextDelete(linecxt);
01859 MemoryContextSwitchTo(oldcxt);
01860
01861 if (!ok)
01862 {
01863
01864 MemoryContextDelete(hbacxt);
01865 return false;
01866 }
01867
01868
01869 if (parsed_hba_context != NULL)
01870 MemoryContextDelete(parsed_hba_context);
01871 parsed_hba_context = hbacxt;
01872 parsed_hba_lines = new_parsed_lines;
01873
01874 return true;
01875 }
01876
01877
01878
01879
01880
01881
01882
01883
01884
01885
01886
01887
01888
01889
01890 static IdentLine *
01891 parse_ident_line(List *line, int line_number)
01892 {
01893 ListCell *field;
01894 List *tokens;
01895 HbaToken *token;
01896 IdentLine *parsedline;
01897
01898 Assert(line != NIL);
01899 field = list_head(line);
01900
01901 parsedline = palloc0(sizeof(IdentLine));
01902 parsedline->linenumber = line_number;
01903
01904
01905 tokens = lfirst(field);
01906 IDENT_MULTI_VALUE(tokens);
01907 token = linitial(tokens);
01908 parsedline->usermap = pstrdup(token->string);
01909
01910
01911 field = lnext(field);
01912 IDENT_FIELD_ABSENT(field);
01913 tokens = lfirst(field);
01914 IDENT_MULTI_VALUE(tokens);
01915 token = linitial(tokens);
01916 parsedline->ident_user = pstrdup(token->string);
01917
01918
01919 field = lnext(field);
01920 IDENT_FIELD_ABSENT(field);
01921 tokens = lfirst(field);
01922 IDENT_MULTI_VALUE(tokens);
01923 token = linitial(tokens);
01924 parsedline->pg_role = pstrdup(token->string);
01925
01926 if (parsedline->ident_user[0] == '/')
01927 {
01928
01929
01930
01931
01932 int r;
01933 pg_wchar *wstr;
01934 int wlen;
01935
01936 wstr = palloc((strlen(parsedline->ident_user + 1) + 1) * sizeof(pg_wchar));
01937 wlen = pg_mb2wchar_with_len(parsedline->ident_user + 1,
01938 wstr, strlen(parsedline->ident_user + 1));
01939
01940 r = pg_regcomp(&parsedline->re, wstr, wlen, REG_ADVANCED, C_COLLATION_OID);
01941 if (r)
01942 {
01943 char errstr[100];
01944
01945 pg_regerror(r, &parsedline->re, errstr, sizeof(errstr));
01946 ereport(LOG,
01947 (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
01948 errmsg("invalid regular expression \"%s\": %s",
01949 parsedline->ident_user + 1, errstr)));
01950
01951 pfree(wstr);
01952 return NULL;
01953 }
01954 pfree(wstr);
01955 }
01956
01957 return parsedline;
01958 }
01959
01960
01961
01962
01963
01964
01965
01966 static void
01967 check_ident_usermap(IdentLine *identLine, const char *usermap_name,
01968 const char *pg_role, const char *ident_user,
01969 bool case_insensitive, bool *found_p, bool *error_p)
01970 {
01971 *found_p = false;
01972 *error_p = false;
01973
01974 if (strcmp(identLine->usermap, usermap_name) != 0)
01975
01976 return;
01977
01978
01979 if (identLine->ident_user[0] == '/')
01980 {
01981
01982
01983
01984
01985
01986
01987 int r;
01988 regmatch_t matches[2];
01989 pg_wchar *wstr;
01990 int wlen;
01991 char *ofs;
01992 char *regexp_pgrole;
01993
01994 wstr = palloc((strlen(ident_user) + 1) * sizeof(pg_wchar));
01995 wlen = pg_mb2wchar_with_len(ident_user, wstr, strlen(ident_user));
01996
01997 r = pg_regexec(&identLine->re, wstr, wlen, 0, NULL, 2, matches, 0);
01998 if (r)
01999 {
02000 char errstr[100];
02001
02002 if (r != REG_NOMATCH)
02003 {
02004
02005 pg_regerror(r, &identLine->re, errstr, sizeof(errstr));
02006 ereport(LOG,
02007 (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
02008 errmsg("regular expression match for \"%s\" failed: %s",
02009 identLine->ident_user + 1, errstr)));
02010 *error_p = true;
02011 }
02012
02013 pfree(wstr);
02014 return;
02015 }
02016 pfree(wstr);
02017
02018 if ((ofs = strstr(identLine->pg_role, "\\1")) != NULL)
02019 {
02020
02021 if (matches[1].rm_so < 0)
02022 {
02023 ereport(LOG,
02024 (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
02025 errmsg("regular expression \"%s\" has no subexpressions as requested by backreference in \"%s\"",
02026 identLine->ident_user + 1, identLine->pg_role)));
02027 *error_p = true;
02028 return;
02029 }
02030
02031
02032
02033
02034
02035 regexp_pgrole = palloc0(strlen(identLine->pg_role) - 2 + (matches[1].rm_eo - matches[1].rm_so) + 1);
02036 strncpy(regexp_pgrole, identLine->pg_role, (ofs - identLine->pg_role));
02037 memcpy(regexp_pgrole + strlen(regexp_pgrole),
02038 ident_user + matches[1].rm_so,
02039 matches[1].rm_eo - matches[1].rm_so);
02040 strcat(regexp_pgrole, ofs + 2);
02041 }
02042 else
02043 {
02044
02045 regexp_pgrole = pstrdup(identLine->pg_role);
02046 }
02047
02048
02049
02050
02051
02052 if (case_insensitive)
02053 {
02054 if (pg_strcasecmp(regexp_pgrole, pg_role) == 0)
02055 *found_p = true;
02056 }
02057 else
02058 {
02059 if (strcmp(regexp_pgrole, pg_role) == 0)
02060 *found_p = true;
02061 }
02062 pfree(regexp_pgrole);
02063
02064 return;
02065 }
02066 else
02067 {
02068
02069 if (case_insensitive)
02070 {
02071 if (pg_strcasecmp(identLine->pg_role, pg_role) == 0 &&
02072 pg_strcasecmp(identLine->ident_user, ident_user) == 0)
02073 *found_p = true;
02074 }
02075 else
02076 {
02077 if (strcmp(identLine->pg_role, pg_role) == 0 &&
02078 strcmp(identLine->ident_user, ident_user) == 0)
02079 *found_p = true;
02080 }
02081 }
02082 return;
02083 }
02084
02085
02086
02087
02088
02089
02090
02091
02092
02093
02094
02095
02096
02097
02098
02099 int
02100 check_usermap(const char *usermap_name,
02101 const char *pg_role,
02102 const char *auth_user,
02103 bool case_insensitive)
02104 {
02105 bool found_entry = false,
02106 error = false;
02107
02108 if (usermap_name == NULL || usermap_name[0] == '\0')
02109 {
02110 if (case_insensitive)
02111 {
02112 if (pg_strcasecmp(pg_role, auth_user) == 0)
02113 return STATUS_OK;
02114 }
02115 else
02116 {
02117 if (strcmp(pg_role, auth_user) == 0)
02118 return STATUS_OK;
02119 }
02120 ereport(LOG,
02121 (errmsg("provided user name (%s) and authenticated user name (%s) do not match",
02122 pg_role, auth_user)));
02123 return STATUS_ERROR;
02124 }
02125 else
02126 {
02127 ListCell *line_cell;
02128
02129 foreach(line_cell, parsed_ident_lines)
02130 {
02131 check_ident_usermap(lfirst(line_cell), usermap_name,
02132 pg_role, auth_user, case_insensitive,
02133 &found_entry, &error);
02134 if (found_entry || error)
02135 break;
02136 }
02137 }
02138 if (!found_entry && !error)
02139 {
02140 ereport(LOG,
02141 (errmsg("no match in usermap \"%s\" for user \"%s\" authenticated as \"%s\"",
02142 usermap_name, pg_role, auth_user)));
02143 }
02144 return found_entry ? STATUS_OK : STATUS_ERROR;
02145 }
02146
02147
02148
02149
02150
02151
02152
02153
02154 bool
02155 load_ident(void)
02156 {
02157 FILE *file;
02158 List *ident_lines = NIL;
02159 List *ident_line_nums = NIL;
02160 ListCell *line_cell,
02161 *num_cell,
02162 *parsed_line_cell;
02163 List *new_parsed_lines = NIL;
02164 bool ok = true;
02165 MemoryContext linecxt;
02166 MemoryContext oldcxt;
02167 MemoryContext ident_context;
02168 IdentLine *newline;
02169
02170 file = AllocateFile(IdentFileName, "r");
02171 if (file == NULL)
02172 {
02173
02174 ereport(LOG,
02175 (errcode_for_file_access(),
02176 errmsg("could not open usermap file \"%s\": %m",
02177 IdentFileName)));
02178 return false;
02179 }
02180
02181 linecxt = tokenize_file(IdentFileName, file, &ident_lines, &ident_line_nums, NULL);
02182 FreeFile(file);
02183
02184
02185 ident_context = AllocSetContextCreate(TopMemoryContext,
02186 "ident parser context",
02187 ALLOCSET_DEFAULT_MINSIZE,
02188 ALLOCSET_DEFAULT_MINSIZE,
02189 ALLOCSET_DEFAULT_MAXSIZE);
02190 oldcxt = MemoryContextSwitchTo(ident_context);
02191 forboth(line_cell, ident_lines, num_cell, ident_line_nums)
02192 {
02193 if ((newline = parse_ident_line(lfirst(line_cell), lfirst_int(num_cell))) == NULL)
02194 {
02195
02196
02197
02198
02199 foreach(parsed_line_cell, new_parsed_lines)
02200 {
02201 newline = (IdentLine *) lfirst(parsed_line_cell);
02202 if (newline->ident_user[0] == '/')
02203 pg_regfree(&newline->re);
02204 }
02205 MemoryContextReset(ident_context);
02206 new_parsed_lines = NIL;
02207 ok = false;
02208
02209
02210
02211
02212
02213
02214 continue;
02215 }
02216
02217 new_parsed_lines = lappend(new_parsed_lines, newline);
02218 }
02219
02220
02221 MemoryContextDelete(linecxt);
02222 MemoryContextSwitchTo(oldcxt);
02223
02224 if (!ok)
02225 {
02226
02227 foreach(parsed_line_cell, new_parsed_lines)
02228 {
02229 newline = (IdentLine *) lfirst(parsed_line_cell);
02230 if (newline->ident_user[0] == '/')
02231 pg_regfree(&newline->re);
02232 }
02233 MemoryContextDelete(ident_context);
02234 return false;
02235 }
02236
02237
02238 if (parsed_ident_lines != NULL)
02239 {
02240 foreach(parsed_line_cell, parsed_ident_lines)
02241 {
02242 newline = (IdentLine *) lfirst(parsed_line_cell);
02243 if (newline->ident_user[0] == '/')
02244 pg_regfree(&newline->re);
02245 }
02246 MemoryContextDelete(parsed_ident_context);
02247 }
02248 parsed_ident_context = ident_context;
02249 parsed_ident_lines = new_parsed_lines;
02250
02251 return true;
02252 }
02253
02254
02255
02256
02257
02258
02259
02260
02261
02262
02263
02264 void
02265 hba_getauthmethod(hbaPort *port)
02266 {
02267 check_hba(port);
02268 }