fe-auth.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 764 行 · 第 1/2 页
C
764 行
/*------------------------------------------------------------------------- * * fe-auth.c * The front-end (client) authorization routines * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * NOTE: the error message strings returned by this module must not * exceed INITIAL_EXPBUFFER_SIZE (currently 256 bytes). * * IDENTIFICATION * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.84.2.3 2003/12/20 18:46:02 tgl Exp $ * *------------------------------------------------------------------------- *//* * INTERFACE ROUTINES * frontend (client) routines: * fe_sendauth send authentication information * fe_getauthname get user's name according to the client side * of the authentication system * fe_setauthsvc set frontend authentication service * fe_getauthsvc get current frontend authentication service * * * */#include "postgres_fe.h"#ifdef WIN32#include "win32.h"#else#include <unistd.h>#include <fcntl.h>#include <errno.h>#include <sys/types.h>#include <sys/param.h> /* for MAXHOSTNAMELEN on most */#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#ifndef MAXHOSTNAMELEN#include <netdb.h> /* for MAXHOSTNAMELEN on some */#endif#include <pwd.h>#endif#ifdef HAVE_CRYPT_H#include <crypt.h>#endif#include "libpq-fe.h"#include "libpq-int.h"#include "fe-auth.h"#include "libpq/crypt.h"/* * common definitions for generic fe/be routines */#define STARTUP_MSG 7 /* Initialise a connection */#define STARTUP_KRB4_MSG 10 /* krb4 session follows */#define STARTUP_KRB5_MSG 11 /* krb5 session follows */#define STARTUP_PASSWORD_MSG 14 /* Password follows */struct authsvc{ const char *name; /* service nickname (for command line) */ MsgType msgtype; /* startup packet header type */ int allowed; /* initially allowed (before command line * option parsing)? */};/* * Command-line parsing routines use this structure to map nicknames * onto service types (and the startup packets to use with them). * * Programs receiving an authentication request use this structure to * decide which authentication service types are currently permitted. * By default, all authentication systems compiled into the system are * allowed. Unauthenticated connections are disallowed unless there * isn't any authentication system. */static const struct authsvc authsvcs[] = {#ifdef KRB4 {"krb4", STARTUP_KRB4_MSG, 1}, {"kerberos", STARTUP_KRB4_MSG, 1},#endif /* KRB4 */#ifdef KRB5 {"krb5", STARTUP_KRB5_MSG, 1}, {"kerberos", STARTUP_KRB5_MSG, 1},#endif /* KRB5 */ {UNAUTHNAME, STARTUP_MSG,#if defined(KRB4) || defined(KRB5) 0#else /* !(KRB4 || KRB5) */ 1#endif /* !(KRB4 || KRB5) */ }, {"password", STARTUP_PASSWORD_MSG, 0}};static const int n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc);#ifdef KRB4/* * MIT Kerberos authentication system - protocol version 4 */#include "krb.h"/* for some reason, this is not defined in krb.h ... */extern char *tkt_string(void);/* * pg_krb4_init -- initialization performed before any Kerberos calls are made * * For v4, all we need to do is make sure the library routines get the right * ticket file if we want them to see a special one. (They will open the file * themselves.) */static voidpg_krb4_init(){ char *realm; static int init_done = 0; if (init_done) return; init_done = 1; /* * If the user set PGREALM, then we use a ticket file with a special * name: <usual-ticket-file-name>@<PGREALM-value> */ if ((realm = getenv("PGREALM"))) { char tktbuf[MAXPGPATH]; (void) snprintf(tktbuf, sizeof(tktbuf), "%s@%s", tkt_string(), realm); krb_set_tkt_string(tktbuf); }}/* * pg_krb4_authname -- returns a pointer to static space containing whatever * name the user has authenticated to the system * * We obtain this information by digging around in the ticket file. */static char *pg_krb4_authname(char *PQerrormsg){ char instance[INST_SZ + 1]; char realm[REALM_SZ + 1]; int status; static char name[SNAME_SZ + 1] = ""; if (name[0]) return name; pg_krb4_init(); name[SNAME_SZ] = '\0'; status = krb_get_tf_fullname(tkt_string(), name, instance, realm); if (status != KSUCCESS) { snprintf(PQerrormsg, PQERRORMSG_LENGTH, "pg_krb4_authname: krb_get_tf_fullname: %s\n", krb_err_txt[status]); return (char *) NULL; } return name;}/* * pg_krb4_sendauth -- client routine to send authentication information to * the server * * This routine does not do mutual authentication, nor does it return enough * information to do encrypted connections. But then, if we want to do * encrypted connections, we'll have to redesign the whole RPC mechanism * anyway. * * If the user is too lazy to feed us a hostname, we try to come up with * something other than "localhost" since the hostname is used as an * instance and instance names in v4 databases are usually actual hostnames * (canonicalized to omit all domain suffixes). */static intpg_krb4_sendauth(char *PQerrormsg, int sock, struct sockaddr_in * laddr, struct sockaddr_in * raddr, const char *hostname){ long krbopts = 0; /* one-way authentication */ KTEXT_ST clttkt; int status; char hostbuf[MAXHOSTNAMELEN]; const char *realm = getenv("PGREALM"); /* NULL == current realm */ if (!hostname || !(*hostname)) { if (gethostname(hostbuf, MAXHOSTNAMELEN) < 0) strcpy(hostbuf, "localhost"); hostname = hostbuf; } pg_krb4_init(); status = krb_sendauth(krbopts, sock, &clttkt, PG_KRB_SRVNAM, hostname, realm, (u_long) 0, (MSG_DAT *) NULL, (CREDENTIALS *) NULL, NULL, laddr, raddr, PG_KRB4_VERSION); if (status != KSUCCESS) { snprintf(PQerrormsg, PQERRORMSG_LENGTH, libpq_gettext("Kerberos 4 error: %s\n"), krb_err_txt[status]); return STATUS_ERROR; } return STATUS_OK;}#endif /* KRB4 */#ifdef KRB5/* * MIT Kerberos authentication system - protocol version 5 */#include <krb5.h>#include <com_err.h>/* * pg_an_to_ln -- return the local name corresponding to an authentication * name * * XXX Assumes that the first aname component is the user name. This is NOT * necessarily so, since an aname can actually be something out of your * worst X.400 nightmare, like * ORGANIZATION=U. C. Berkeley/NAME=Paul M. Aoki@CS.BERKELEY.EDU * Note that the MIT an_to_ln code does the same thing if you don't * provide an aname mapping database...it may be a better idea to use * krb5_an_to_ln, except that it punts if multiple components are found, * and we can't afford to punt. */static char *pg_an_to_ln(char *aname){ char *p; if ((p = strchr(aname, '/')) || (p = strchr(aname, '@'))) *p = '\0'; return aname;}/* * Various krb5 state which is not connection specific, and a flag to * indicate whether we have initialised it yet. */static int pg_krb5_initialised;static krb5_context pg_krb5_context;static krb5_ccache pg_krb5_ccache;static krb5_principal pg_krb5_client;static char *pg_krb5_name;static intpg_krb5_init(char *PQerrormsg){ krb5_error_code retval; if (pg_krb5_initialised) return STATUS_OK; retval = krb5_init_context(&pg_krb5_context); if (retval) { snprintf(PQerrormsg, PQERRORMSG_LENGTH, "pg_krb5_init: krb5_init_context: %s\n", error_message(retval)); return STATUS_ERROR; } retval = krb5_cc_default(pg_krb5_context, &pg_krb5_ccache); if (retval) { snprintf(PQerrormsg, PQERRORMSG_LENGTH, "pg_krb5_init: krb5_cc_default: %s\n", error_message(retval)); krb5_free_context(pg_krb5_context); return STATUS_ERROR; } retval = krb5_cc_get_principal(pg_krb5_context, pg_krb5_ccache, &pg_krb5_client); if (retval) { snprintf(PQerrormsg, PQERRORMSG_LENGTH, "pg_krb5_init: krb5_cc_get_principal: %s\n", error_message(retval)); krb5_cc_close(pg_krb5_context, pg_krb5_ccache); krb5_free_context(pg_krb5_context); return STATUS_ERROR; } retval = krb5_unparse_name(pg_krb5_context, pg_krb5_client, &pg_krb5_name); if (retval) { snprintf(PQerrormsg, PQERRORMSG_LENGTH, "pg_krb5_init: krb5_unparse_name: %s\n", error_message(retval)); krb5_free_principal(pg_krb5_context, pg_krb5_client); krb5_cc_close(pg_krb5_context, pg_krb5_ccache); krb5_free_context(pg_krb5_context); return STATUS_ERROR; } pg_krb5_name = pg_an_to_ln(pg_krb5_name); pg_krb5_initialised = 1; return STATUS_OK;}/* * pg_krb5_authname -- returns a pointer to static space containing whatever * name the user has authenticated to the system */static const char *pg_krb5_authname(char *PQerrormsg){ if (pg_krb5_init(PQerrormsg) != STATUS_OK) return NULL; return pg_krb5_name;}/* * pg_krb5_sendauth -- client routine to send authentication information to * the server */static intpg_krb5_sendauth(char *PQerrormsg, int sock, const char *hostname){ krb5_error_code retval; int ret; krb5_principal server; krb5_auth_context auth_context = NULL; krb5_error *err_ret = NULL; int flags; ret = pg_krb5_init(PQerrormsg); if (ret != STATUS_OK) return ret; retval = krb5_sname_to_principal(pg_krb5_context, hostname, PG_KRB_SRVNAM, KRB5_NT_SRV_HST, &server); if (retval) { snprintf(PQerrormsg, PQERRORMSG_LENGTH, "pg_krb5_sendauth: krb5_sname_to_principal: %s\n", error_message(retval)); return STATUS_ERROR; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?