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 + -
显示快捷键?