📄 hba.c
字号:
check_db(const char *dbname, const char *role, char *param_str){ char *tok; for (tok = strtok(param_str, MULTI_VALUE_SEP); tok != NULL; tok = strtok(NULL, MULTI_VALUE_SEP)) { if (strcmp(tok, "all\n") == 0) return true; else if (strcmp(tok, "sameuser\n") == 0) { if (strcmp(dbname, role) == 0) return true; } else if (strcmp(tok, "samegroup\n") == 0 || strcmp(tok, "samerole\n") == 0) { if (is_member(role, dbname)) return true; } else if (strcmp(tok, dbname) == 0) return true; } return false;}/* * Scan the rest of a host record (after the mask field) * and return the interpretation of it as *userauth_p, *auth_arg_p, and * *error_p. *line_item points to the next token of the line, and is * advanced over successfully-read tokens. */static voidparse_hba_auth(ListCell **line_item, UserAuth *userauth_p, char **auth_arg_p, bool *error_p){ char *token; *auth_arg_p = NULL; if (!*line_item) { *error_p = true; return; } token = lfirst(*line_item); if (strcmp(token, "trust") == 0) *userauth_p = uaTrust; else if (strcmp(token, "ident") == 0) *userauth_p = uaIdent; else if (strcmp(token, "password") == 0) *userauth_p = uaPassword; else if (strcmp(token, "krb5") == 0) *userauth_p = uaKrb5; else if (strcmp(token, "reject") == 0) *userauth_p = uaReject; else if (strcmp(token, "md5") == 0) *userauth_p = uaMD5; else if (strcmp(token, "crypt") == 0) *userauth_p = uaCrypt;#ifdef USE_PAM else if (strcmp(token, "pam") == 0) *userauth_p = uaPAM;#endif else { *error_p = true; return; } *line_item = lnext(*line_item); /* Get the authentication argument token, if any */ if (*line_item) { token = lfirst(*line_item); *auth_arg_p = pstrdup(token); *line_item = lnext(*line_item); /* If there is more on the line, it is an error */ if (*line_item) *error_p = true; }}/* * Process one line from the hba config file. * * See if it applies to a connection from a host with IP address port->raddr * to a database named port->database. If so, return *found_p true * and fill in the auth arguments into the appropriate port fields. * If not, leave *found_p as it was. If the record has a syntax error, * return *error_p true, after issuing a message to the log. If no error, * leave *error_p as it was. */static voidparse_hba(List *line, int line_num, hbaPort *port, bool *found_p, bool *error_p){ char *token; char *db; char *role; struct addrinfo *gai_result; struct addrinfo hints; int ret; struct sockaddr_storage addr; struct sockaddr_storage mask; char *cidr_slash; ListCell *line_item; line_item = list_head(line); /* Check the record type. */ token = lfirst(line_item); if (strcmp(token, "local") == 0) { /* Get the database. */ line_item = lnext(line_item); if (!line_item) goto hba_syntax; db = lfirst(line_item); /* Get the role. */ line_item = lnext(line_item); if (!line_item) goto hba_syntax; role = lfirst(line_item); line_item = lnext(line_item); if (!line_item) goto hba_syntax; /* Read the rest of the line. */ parse_hba_auth(&line_item, &port->auth_method, &port->auth_arg, error_p); if (*error_p) goto hba_syntax; /* Disallow auth methods that always need TCP/IP sockets to work */ if (port->auth_method == uaKrb5) goto hba_syntax; /* Does not match if connection isn't AF_UNIX */ if (!IS_AF_UNIX(port->raddr.addr.ss_family)) return; } else if (strcmp(token, "host") == 0 || strcmp(token, "hostssl") == 0 || strcmp(token, "hostnossl") == 0) { if (token[4] == 's') /* "hostssl" */ {#ifdef USE_SSL /* Record does not match if we are not on an SSL connection */ if (!port->ssl) return; /* Placeholder to require specific SSL level, perhaps? */ /* Or a client certificate */ /* Since we were on SSL, proceed as with normal 'host' mode */#else /* We don't accept this keyword at all if no SSL support */ goto hba_syntax;#endif }#ifdef USE_SSL else if (token[4] == 'n') /* "hostnossl" */ { /* Record does not match if we are on an SSL connection */ if (port->ssl) return; }#endif /* Get the database. */ line_item = lnext(line_item); if (!line_item) goto hba_syntax; db = lfirst(line_item); /* Get the role. */ line_item = lnext(line_item); if (!line_item) goto hba_syntax; role = lfirst(line_item); /* Read the IP address field. (with or without CIDR netmask) */ line_item = lnext(line_item); if (!line_item) goto hba_syntax; token = lfirst(line_item); /* Check if it has a CIDR suffix and if so isolate it */ cidr_slash = strchr(token, '/'); if (cidr_slash) *cidr_slash = '\0'; /* Get the IP address either way */ hints.ai_flags = AI_NUMERICHOST; hints.ai_family = PF_UNSPEC; hints.ai_socktype = 0; hints.ai_protocol = 0; hints.ai_addrlen = 0; hints.ai_canonname = NULL; hints.ai_addr = NULL; hints.ai_next = NULL; ret = pg_getaddrinfo_all(token, NULL, &hints, &gai_result); if (ret || !gai_result) { ereport(LOG, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("invalid IP address \"%s\" in file \"%s\" line %d: %s", token, HbaFileName, line_num, gai_strerror(ret)))); if (cidr_slash) *cidr_slash = '/'; if (gai_result) pg_freeaddrinfo_all(hints.ai_family, gai_result); goto hba_other_error; } if (cidr_slash) *cidr_slash = '/'; memcpy(&addr, gai_result->ai_addr, gai_result->ai_addrlen); pg_freeaddrinfo_all(hints.ai_family, gai_result); /* Get the netmask */ if (cidr_slash) { if (pg_sockaddr_cidr_mask(&mask, cidr_slash + 1, addr.ss_family) < 0) goto hba_syntax; } else { /* Read the mask field. */ line_item = lnext(line_item); if (!line_item) goto hba_syntax; token = lfirst(line_item); ret = pg_getaddrinfo_all(token, NULL, &hints, &gai_result); if (ret || !gai_result) { ereport(LOG, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("invalid IP mask \"%s\" in file \"%s\" line %d: %s", token, HbaFileName, line_num, gai_strerror(ret)))); if (gai_result) pg_freeaddrinfo_all(hints.ai_family, gai_result); goto hba_other_error; } memcpy(&mask, gai_result->ai_addr, gai_result->ai_addrlen); pg_freeaddrinfo_all(hints.ai_family, gai_result); if (addr.ss_family != mask.ss_family) { ereport(LOG, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("IP address and mask do not match in file \"%s\" line %d", HbaFileName, line_num))); goto hba_other_error; } } if (addr.ss_family != port->raddr.addr.ss_family) { /* * Wrong address family. We allow only one case: if the file has * IPv4 and the port is IPv6, promote the file address to IPv6 and * try to match that way. */#ifdef HAVE_IPV6 if (addr.ss_family == AF_INET && port->raddr.addr.ss_family == AF_INET6) { pg_promote_v4_to_v6_addr(&addr); pg_promote_v4_to_v6_mask(&mask); } else#endif /* HAVE_IPV6 */ { /* Line doesn't match client port, so ignore it. */ return; } } /* Ignore line if client port is not in the matching addr range. */ if (!pg_range_sockaddr(&port->raddr.addr, &addr, &mask)) return; /* Read the rest of the line. */ line_item = lnext(line_item); if (!line_item) goto hba_syntax; parse_hba_auth(&line_item, &port->auth_method, &port->auth_arg, error_p); if (*error_p) goto hba_syntax; } else goto hba_syntax; /* Does the entry match database and role? */ if (!check_db(port->database_name, port->user_name, db)) return; if (!check_role(port->user_name, role)) return; /* Success */ *found_p = true; return;hba_syntax: if (line_item) ereport(LOG, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("invalid entry in file \"%s\" at line %d, token \"%s\"", HbaFileName, line_num, (char *) lfirst(line_item)))); else ereport(LOG, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("missing field in file \"%s\" at end of line %d", HbaFileName, line_num))); /* Come here if suitable message already logged */hba_other_error: *error_p = true;}/* * Scan the (pre-parsed) hba file line by line, looking for a match * to the port's connection request. */static boolcheck_hba(hbaPort *port){ bool found_entry = false; bool error = false; ListCell *line; ListCell *line_num; forboth(line, hba_lines, line_num, hba_line_nums) { parse_hba(lfirst(line), lfirst_int(line_num), port, &found_entry, &error); if (found_entry || error) break; } if (!error) { /* If no matching entry was found, synthesize 'reject' entry. */ if (!found_entry) port->auth_method = uaReject; return true; } else return false;}/* * Load role/password mapping file */voidload_role(void){ char *filename; FILE *role_file; /* Discard any old data */ if (role_lines || role_line_nums) free_lines(&role_lines, &role_line_nums); if (role_sorted) pfree(role_sorted); role_sorted = NULL; role_length = 0; /* Read in the file contents */ filename = auth_getflatfilename(); role_file = AllocateFile(filename, "r"); if (role_file == NULL) { /* no complaint if not there */ if (errno != ENOENT) ereport(LOG, (errcode_for_file_access(), errmsg("could not open file \"%s\": %m", filename))); pfree(filename); return; } tokenize_file(filename, role_file, &role_lines, &role_line_nums); FreeFile(role_file); pfree(filename); /* create array for binary searching */ role_length = list_length(role_lines); if (role_length) { int i = 0; ListCell *line; /* We assume the flat file was written already-sorted */ role_sorted = palloc(role_length * sizeof(List *)); foreach(line, role_lines) role_sorted[i++] = lfirst(line); }}/* * Read the config file and create a List of Lists of tokens in the file. */voidload_hba(void){ FILE *file; if (hba_lines || hba_line_nums) free_lines(&hba_lines, &hba_line_nums); file = AllocateFile(HbaFileName, "r"); /* Failure is fatal since with no HBA entries we can do nothing... */ if (file == NULL) ereport(FATAL, (errcode_for_file_access(), errmsg("could not open configuration file \"%s\": %m", HbaFileName))); tokenize_file(HbaFileName, file, &hba_lines, &hba_line_nums); FreeFile(file);}/* * Read and parse one line from the flat pg_database file. * * Returns TRUE on success, FALSE if EOF; bad data causes elog(FATAL). * * Output parameters: * dbname: gets database name (must be of size NAMEDATALEN bytes) * dboid: gets database OID * dbtablespace: gets database's default tablespace's OID * dbfrozenxid: gets database's frozen XID * dbvacuumxid: gets database's vacuum XID * * This is not much related to the other functions in hba.c, but we put it * here because it uses the next_token() infrastructure. */boolread_pg_database_line(FILE *fp, char *dbname, Oid *dboid, Oid *dbtablespace, TransactionId *dbfrozenxid, TransactionId *dbvacuumxid){ char buf[MAX_TOKEN]; if (feof(fp)) return false; if (!next_token(fp, buf, sizeof(buf))) return false; if (strlen(buf) >= NAMEDATALEN) elog(FATAL, "bad data in flat pg_database file"); strcpy(dbname, buf); next_token(fp, buf, sizeof(buf)); if (!isdigit((unsigned char) buf[0])) elog(FATAL, "bad data in flat pg_database file"); *dboid = atooid(buf); next_token(fp, buf, sizeof(buf)); if (!isdigit((unsigned char) buf[0])) elog(FATAL, "bad data in flat pg_database file"); *dbtablespace = atooid(buf); next_token(fp, buf, sizeof(buf)); if (!isdigit((unsigned char) buf[0])) elog(FATAL, "bad data in flat pg_database file"); *dbfrozenxid = atoxid(buf); next_token(fp, buf, sizeof(buf)); if (!isdigit((unsigned char) buf[0])) elog(FATAL, "bad data in flat pg_database file"); *dbvacuumxid = atoxid(buf); /* expect EOL next */ if (next_token(fp, buf, sizeof(buf))) elog(FATAL, "bad data in flat pg_database file"); return true;}/* * Process one line from the ident config file. * * Take the line and compare it to the needed map, pg_role and ident_user. * *found_p and *error_p are set according to our results. */static voidparse_ident_usermap(List *line, int line_number, const char *usermap_name, const char *pg_role, const char *ident_user, bool *found_p, bool *error_p){ ListCell *line_item; char *token; char *file_map; char *file_pgrole; char *file_ident_user; *found_p = false; *error_p = false; Assert(line != NIL); line_item = list_head(line); /* Get the map token (must exist) */ token = lfirst(line_item); file_map = token; /* Get the ident user token */ line_item = lnext(line_item); if (!line_item) goto ident_syntax; token = lfirst(line_item); file_ident_user = token; /* Get the PG rolename token */ line_item = lnext(line_item); if (!line_item) goto ident_syntax; token = lfirst(line_item); file_pgrole = token; /* Match? */ if (strcmp(file_map, usermap_name) == 0 && strcmp(file_pgrole, pg_role) == 0 && strcmp(file_ident_user, ident_user) == 0) *found_p = true; return;ident_syntax: ereport(LOG,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -