hba.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,584 行 · 第 1/3 页
C
1,584 行
/*------------------------------------------------------------------------- * * hba.c * Routines to handle host based authentication (that's the scheme * wherein you authenticate a user by seeing what IP address the system * says he comes from and possibly using ident). * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.116.2.3 2004/09/18 01:23:12 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include <errno.h>#include <pwd.h>#include <fcntl.h>#include <sys/param.h>#include <sys/socket.h>#if defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || defined(HAVE_STRUCT_SOCKCRED)#include <sys/uio.h>#include <sys/ucred.h>#endif#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#include "commands/user.h"#include "libpq/crypt.h"#include "libpq/libpq.h"#include "miscadmin.h"#include "nodes/pg_list.h"#include "storage/fd.h"#define IDENT_USERNAME_MAX 512/* Max size of username ident server can return *//* This is used to separate values in multi-valued column strings */#define MULTI_VALUE_SEP "\001"/* * These variables hold the pre-parsed contents of the hba and ident * configuration files. Each is a list of sublists, one sublist for * each (non-empty, non-comment) line of the file. Each sublist's * first item is an integer line number (so we can give somewhat-useful * location info in error messages). Remaining items are palloc'd strings, * one string per token on the line. Note there will always be at least * one token, since blank lines are not entered in the data structure. */static List *hba_lines = NIL; /* pre-parsed contents of hba file */static List *ident_lines = NIL; /* pre-parsed contents of ident file */static List *group_lines = NIL; /* pre-parsed contents of group file */static List *user_lines = NIL; /* pre-parsed contents of user password * file *//* sorted entries so we can do binary search lookups */static List **user_sorted = NULL; /* sorted user list, for bsearch() */static List **group_sorted = NULL; /* sorted group list, for * bsearch() */static int user_length;static int group_length;static List *tokenize_file(FILE *file);static char *tokenize_inc_file(const char *inc_filename);/* * isblank() exists in the ISO C99 spec, but it's not very portable yet, * so provide our own version. */static boolpg_isblank(const char c){ return c == ' ' || c == '\t' || c == '\r';}/* * Grab one token out of fp. Tokens are strings of non-blank * characters bounded by blank characters, beginning of line, and * end of line. Blank means space or tab. Return the token as * *buf. Leave file positioned to character immediately after the * token or EOF, whichever comes first. If no more tokens on line, * return null string as *buf and position file to beginning of * next line or EOF, whichever comes first. Allow spaces in quoted * strings. Terminate on unquoted commas. Handle comments. */voidnext_token(FILE *fp, char *buf, const int bufsz){ int c; char *start_buf = buf; char *end_buf = buf + (bufsz - 1); bool in_quote = false; bool was_quote = false; /* Move over initial whitespace and commas */ while ((c = getc(fp)) != EOF && (pg_isblank(c) || c == ',')) ; if (c != EOF && c != '\n') { /* * Build a token in buf of next characters up to EOF, EOL, * unquoted comma, or unquoted whitespace. */ while (c != EOF && c != '\n' && (!pg_isblank(c) || in_quote == true)) { /* skip comments to EOL */ if (c == '#' && !in_quote) { while ((c = getc(fp)) != EOF && c != '\n') ; /* If only comment, consume EOL too; return EOL */ if (c != EOF && buf == start_buf) c = getc(fp); break; } if (buf >= end_buf) { *buf = '\0'; ereport(LOG, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("authentication file token too long, skipping: \"%s\"", start_buf))); /* Discard remainder of line */ while ((c = getc(fp)) != EOF && c != '\n') ; break; } if (c != '"' || (c == '"' && was_quote)) *buf++ = c; /* We pass back the comma so the caller knows there is more */ if ((pg_isblank(c) || c == ',') && !in_quote) break; /* Literal double-quote is two double-quotes */ if (in_quote && c == '"') was_quote = !was_quote; else was_quote = false; if (c == '"') in_quote = !in_quote; c = getc(fp); } /* * Put back the char right after the token (critical in case it is * EOL, since we need to detect end-of-line at next call). */ if (c != EOF) ungetc(c, fp); } *buf = '\0';}/* * Tokenize file and handle file inclusion and comma lists. We have * to break apart the commas to expand any file names then * reconstruct with commas. * * The result is always a palloc'd string. If it's zero-length then * we have reached EOL. */static char *next_token_expand(FILE *file){ char buf[MAX_TOKEN]; char *comma_str = pstrdup(""); bool trailing_comma; char *incbuf; do { next_token(file, buf, sizeof(buf)); if (!*buf) break; if (buf[strlen(buf) - 1] == ',') { trailing_comma = true; buf[strlen(buf) - 1] = '\0'; } else trailing_comma = false; /* Is this referencing a file? */ if (buf[0] == '@') incbuf = tokenize_inc_file(buf + 1); else incbuf = pstrdup(buf); comma_str = repalloc(comma_str, strlen(comma_str) + strlen(incbuf) + 1); strcat(comma_str, incbuf); pfree(incbuf); if (trailing_comma) { comma_str = repalloc(comma_str, strlen(comma_str) + 1 + 1); strcat(comma_str, MULTI_VALUE_SEP); } } while (trailing_comma); return comma_str;}/* * Free memory used by lines/tokens (i.e., structure built by tokenize_file) */static voidfree_lines(List **lines){ if (*lines) { List *line, *token; foreach(line, *lines) { List *ln = lfirst(line); /* free the pstrdup'd tokens (don't try it on the line number) */ foreach(token, lnext(ln)) pfree(lfirst(token)); /* free the sublist structure itself */ freeList(ln); } /* free the list structure itself */ freeList(*lines); /* clear the static variable */ *lines = NIL; }}static char *tokenize_inc_file(const char *inc_filename){ char *inc_fullname; FILE *inc_file; List *inc_lines; List *line; char *comma_str = pstrdup(""); inc_fullname = (char *) palloc(strlen(DataDir) + 1 + strlen(inc_filename) + 1); strcpy(inc_fullname, DataDir); strcat(inc_fullname, "/"); strcat(inc_fullname, inc_filename); inc_file = AllocateFile(inc_fullname, "r"); if (!inc_file) { ereport(LOG, (errcode_for_file_access(), errmsg("could not open secondary authentication file \"@%s\" as \"%s\": %m", inc_filename, inc_fullname))); pfree(inc_fullname); /* return empty string, it matches nothing */ return pstrdup(""); } pfree(inc_fullname); /* There is possible recursion here if the file contains @ */ inc_lines = tokenize_file(inc_file); FreeFile(inc_file); /* Create comma-separate string from List */ foreach(line, inc_lines) { List *ln = lfirst(line); List *token; /* First entry is line number */ foreach(token, lnext(ln)) { if (strlen(comma_str)) { comma_str = repalloc(comma_str, strlen(comma_str) + 1); strcat(comma_str, MULTI_VALUE_SEP); } comma_str = repalloc(comma_str, strlen(comma_str) + strlen(lfirst(token)) + 1); strcat(comma_str, lfirst(token)); } } free_lines(&inc_lines); return comma_str;}/* * Read the given file and create a list of line sublists. */static List *tokenize_file(FILE *file){ List *lines = NIL; List *next_line = NIL; int line_number = 1; char *buf; while (!feof(file)) { buf = next_token_expand(file); /* add token to list, unless we are at EOL or comment start */ if (buf[0] != '\0') { if (next_line == NIL) { /* make a new line List */ next_line = makeListi1(line_number); lines = lappend(lines, next_line); } /* append token to current line's list */ next_line = lappend(next_line, buf); } else { /* we are at real or logical EOL, so force a new line List */ next_line = NIL; /* Don't forget to pfree the next_token_expand result */ pfree(buf); } /* Advance line number whenever we reach EOL */ if (next_line == NIL) line_number++; } return lines;}/* * Compare two lines based on their user/group names. * * Used for qsort() sorting. */static intuser_group_qsort_cmp(const void *list1, const void *list2){ /* first node is line number */ char *user1 = lfirst(lnext(*(List **) list1)); char *user2 = lfirst(lnext(*(List **) list2)); return strcmp(user1, user2);}/* * Compare two lines based on their user/group names. * * Used for bsearch() lookup. */static intuser_group_bsearch_cmp(const void *user, const void *list){ /* first node is line number */ char *user2 = lfirst(lnext(*(List **) list)); return strcmp(user, user2);}/* * Lookup a group name in the pg_group file */static List **get_group_line(const char *group){ /* On some versions of Solaris, bsearch of zero items dumps core */ if (group_length == 0) return NULL; return (List **) bsearch((void *) group, (void *) group_sorted, group_length, sizeof(List *), user_group_bsearch_cmp);}/* * Lookup a user name in the pg_shadow file */List **get_user_line(const char *user){ /* On some versions of Solaris, bsearch of zero items dumps core */ if (user_length == 0) return NULL; return (List **) bsearch((void *) user, (void *) user_sorted, user_length, sizeof(List *), user_group_bsearch_cmp);}/* * Check group for a specific user. */static boolcheck_group(char *group, char *user){ List **line, *l; if ((line = get_group_line(group)) != NULL) { foreach(l, lnext(lnext(*line))) if (strcmp(lfirst(l), user) == 0) return true; } return false;}/* * Check comma user list for a specific user, handle group names. */static boolcheck_user(char *user, char *param_str){ char *tok; for (tok = strtok(param_str, MULTI_VALUE_SEP); tok != NULL; tok = strtok(NULL, MULTI_VALUE_SEP)) { if (tok[0] == '+') { if (check_group(tok + 1, user)) return true; } else if (strcmp(tok, user) == 0 || strcmp(tok, "all") == 0) return true; } return false;}/* * Check to see if db/user combination matches param string. */static boolcheck_db(char *dbname, char *user, 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") == 0) return true; else if (strcmp(tok, "sameuser") == 0) { if (strcmp(dbname, user) == 0) return true; } else if (strcmp(tok, "samegroup") == 0) { if (check_group(dbname, user)) 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 points to the next token of the line. */static voidparse_hba_auth(List *line, UserAuth *userauth_p, char **auth_arg_p, bool *error_p){ char *token; *auth_arg_p = NULL; if (!line) *error_p = true; else { /* Get authentication type token. */ token = lfirst(line); 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, "krb4") == 0) *userauth_p = uaKrb4; 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
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?