login.c

来自「在Linux/Unix下面访问WINDOWS SQLSERVER 的ODBC驱动」· C语言 代码 · 共 1,031 行 · 第 1/2 页

C
1,031
字号
/* FreeTDS - Library of routines accessing Sybase and Microsoft databases * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005  Brian Bruns * Copyright (C) 2005, 2006, 2007  Ziglio Frediano * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */#if HAVE_CONFIG_H#include <config.h>#endif /* HAVE_CONFIG_H */#include <stdarg.h>#include <stdio.h>#if HAVE_STDLIB_H#include <stdlib.h>#endif /* HAVE_STDLIB_H */#include <assert.h>#if HAVE_STRING_H#include <string.h>#endif /* HAVE_STRING_H */#if HAVE_UNISTD_H#include <unistd.h>#endif /* HAVE_UNISTD_H */#ifdef WIN32#include <process.h>#endif#include "tds.h"#include "tdsiconv.h"#include "tdsstring.h"#include "replacements.h"#ifdef DMALLOC#include <dmalloc.h>#endifTDS_RCSID(var, "$Id: login.c,v 1.172 2007/12/31 10:06:50 freddy77 Exp $");static int tds_send_login(TDSSOCKET * tds, TDSCONNECTION * connection);static int tds8_do_login(TDSSOCKET * tds, TDSCONNECTION * connection);static int tds7_send_login(TDSSOCKET * tds, TDSCONNECTION * connection);voidtds_set_version(TDSLOGIN * tds_login, TDS_TINYINT major_ver, TDS_TINYINT minor_ver){	tds_login->major_version = major_ver;	tds_login->minor_version = minor_ver;}voidtds_set_packet(TDSLOGIN * tds_login, int packet_size){	tds_login->block_size = packet_size;}voidtds_set_port(TDSLOGIN * tds_login, int port){	tds_login->port = port;}voidtds_set_passwd(TDSLOGIN * tds_login, const char *password){	if (password) {		tds_dstr_zero(&tds_login->password);		tds_dstr_copy(&tds_login->password, password);	}}voidtds_set_bulk(TDSLOGIN * tds_login, TDS_TINYINT enabled){	tds_login->bulk_copy = enabled ? 0 : 1;}voidtds_set_user(TDSLOGIN * tds_login, const char *username){	tds_dstr_copy(&tds_login->user_name, username);}voidtds_set_host(TDSLOGIN * tds_login, const char *hostname){	tds_dstr_copy(&tds_login->client_host_name, hostname);}voidtds_set_app(TDSLOGIN * tds_login, const char *application){	tds_dstr_copy(&tds_login->app_name, application);}/** * \brief Set the servername in a TDSLOGIN structure * * Normally copies \a server into \a tds_login.  If \a server does not point to a plausible name, the environment  * variables TDSQUERY and DSQUERY are used, in that order.  If they don't exist, the "default default" servername * is "SYBASE" (although the utility of that choice is a bit murky).   * * \param tds_login	points to a TDSLOGIN structure * \param server	the servername, or NULL, or a zero-length string * \todo open the log file earlier, so these messages can be seen.   */voidtds_set_server(TDSLOGIN * tds_login, const char *server){	if (!server || strlen(server) == 0) {		server = getenv("TDSQUERY");		tdsdump_log(TDS_DBG_INFO1, "Setting 'server_name' to '%s' from $TDSQUERY.\n", server);	}	if (!server || strlen(server) == 0) {		server = getenv("DSQUERY");		tdsdump_log(TDS_DBG_INFO1, "Setting 'server_name' to '%s' from $DSQUERY.\n", server);	}	if (!server || strlen(server) == 0) {		server = "SYBASE";		tdsdump_log(TDS_DBG_INFO1, "Setting 'server_name' to '%s' (compiled-in default).\n", server);	}	tds_dstr_copy(&tds_login->server_name, server);}voidtds_set_server_addr(TDSLOGIN * tds_login, const char *server_addr){	if (server_addr) {		tds_dstr_copy(&tds_login->server_addr, server_addr);	}}voidtds_set_library(TDSLOGIN * tds_login, const char *library){	tds_dstr_copy(&tds_login->library, library);}voidtds_set_client_charset(TDSLOGIN * tds_login, const char *charset){	tds_dstr_copy(&tds_login->client_charset, charset);}voidtds_set_language(TDSLOGIN * tds_login, const char *language){	tds_dstr_copy(&tds_login->language, language);}voidtds_set_capabilities(TDSLOGIN * tds_login, unsigned char *capabilities, int size){	memcpy(tds_login->capabilities, capabilities, size > TDS_MAX_CAPABILITY ? TDS_MAX_CAPABILITY : size);}struct tds_save_msg{	TDSMESSAGE msg;	char type;};struct tds_save_env{	char *oldval;	char *newval;	int type;};typedef struct tds_save_context{	/* must be first !!! */	TDSCONTEXT ctx;	unsigned num_msg;	struct tds_save_msg msgs[10];	unsigned num_env;	struct tds_save_env envs[10];} TDSSAVECONTEXT;static voidtds_save(TDSSAVECONTEXT *ctx, char type, TDSMESSAGE *msg){	struct tds_save_msg *dest_msg;	if (ctx->num_msg >= TDS_VECTOR_SIZE(ctx->msgs))		return;	dest_msg = &ctx->msgs[ctx->num_msg];	dest_msg->type = type;	dest_msg->msg = *msg;#define COPY(name) if (msg->name) dest_msg->msg.name = strdup(msg->name);	COPY(server);	COPY(message);	COPY(proc_name);	COPY(sql_state);#undef COPY	++ctx->num_msg;}static inttds_save_msg(const TDSCONTEXT *ctx, TDSSOCKET *tds, TDSMESSAGE *msg){	tds_save((TDSSAVECONTEXT *) ctx, 0, msg);	return 0;}static inttds_save_err(const TDSCONTEXT *ctx, TDSSOCKET *tds, TDSMESSAGE *msg){	tds_save((TDSSAVECONTEXT *) ctx, 1, msg);	return TDS_INT_CANCEL;}static voidtds_save_env(TDSSOCKET * tds, int type, char *oldval, char *newval){	TDSSAVECONTEXT *ctx;	struct tds_save_env *env;	if (tds->tds_ctx->msg_handler != tds_save_msg)		return;	ctx = (TDSSAVECONTEXT *) tds->tds_ctx;	if (ctx->num_env >= TDS_VECTOR_SIZE(ctx->envs))		return;	env = &ctx->envs[ctx->num_env];	env->type = type;	env->oldval = oldval ? strdup(oldval) : NULL;	env->newval = newval ? strdup(newval) : NULL;	++ctx->num_env;}static voidinit_save_context(TDSSAVECONTEXT *ctx, const TDSCONTEXT *old_ctx){	memset(ctx, 0, sizeof(*ctx));	ctx->ctx.locale = old_ctx->locale;	ctx->ctx.msg_handler = tds_save_msg;	ctx->ctx.err_handler = tds_save_err;}static voidreplay_save_context(TDSSOCKET *tds, TDSSAVECONTEXT *ctx){	unsigned n;	/* replay all recorded messages */	for (n = 0; n < ctx->num_msg; ++n)		if (ctx->msgs[n].type == 0) {			if (tds->tds_ctx->msg_handler)				tds->tds_ctx->msg_handler(tds->tds_ctx, tds, &ctx->msgs[n].msg);		} else {			if (tds->tds_ctx->err_handler)				tds->tds_ctx->err_handler(tds->tds_ctx, tds, &ctx->msgs[n].msg);		}	/* replay all recorded envs */	for (n = 0; n < ctx->num_env; ++n)		if (tds->env_chg_func)			tds->env_chg_func(tds, ctx->envs[n].type, ctx->envs[n].oldval, ctx->envs[n].newval);}static voidreset_save_context(TDSSAVECONTEXT *ctx){	unsigned n;	/* free all messages */	for (n = 0; n < ctx->num_msg; ++n)		tds_free_msg(&ctx->msgs[n].msg);	ctx->num_msg = 0;	/* free all envs */	for (n = 0; n < ctx->num_env; ++n) {		free(ctx->envs[n].oldval);		free(ctx->envs[n].newval);	}	ctx->num_env = 0;}static voidfree_save_context(TDSSAVECONTEXT *ctx){	reset_save_context(ctx);}/** * Do a connection to socket * @param tds connection structure. This should be a non-connected connection. * @param connection info for connection * @return TDS_FAIL or TDS_SUCCEED */inttds_connect(TDSSOCKET * tds, TDSCONNECTION * connection){	int retval;	int connect_timeout = 0;	int db_selected = 0;	char version[64];	char *str;	int len;		/*	 * A major version of 0 means try to guess the TDS version. 	 * We try them in an order that should work. 	 */	const static struct tdsver {		TDS_TINYINT major_version;		TDS_TINYINT minor_version;	} versions[] =		{ { 8, 0 }		, { 7, 0 }		, { 5, 0 }		, { 4, 2 }		};	if (connection->major_version == 0) {		unsigned int i;		TDSSAVECONTEXT save_ctx;		const TDSCONTEXT *old_ctx = tds->tds_ctx;		typedef void (*env_chg_func_t) (TDSSOCKET * tds, int type, char *oldval, char *newval);		env_chg_func_t old_env_chg = tds->env_chg_func;		init_save_context(&save_ctx, old_ctx);		tds->tds_ctx = &save_ctx.ctx;		tds->env_chg_func = tds_save_env;		for (i=0; i < TDS_VECTOR_SIZE(versions); ++i) {			connection->major_version = versions[i].major_version;			connection->minor_version = versions[i].minor_version;			/* fprintf(stdout, "trying TDSVER %d.%d\n", connection->major_version, connection->minor_version); */			reset_save_context(&save_ctx);			retval = tds_connect(tds, connection);			if (TDS_SUCCEED == retval)				break;			tds_close_socket(tds);		}		tds->env_chg_func = old_env_chg;		tds->tds_ctx = old_ctx;		replay_save_context(tds, &save_ctx);		free_save_context(&save_ctx);		return retval;	}		/*	 * If a dump file has been specified, start logging	 */	if (!tds_dstr_isempty(&connection->dump_file)) {		if (connection->debug_flags)			tds_debug_flags = connection->debug_flags;		tdsdump_open(tds_dstr_cstr(&connection->dump_file));	}	tds->connection = connection;	tds->major_version = connection->major_version;	tds->minor_version = connection->minor_version;	tds->emul_little_endian = connection->emul_little_endian;#ifdef WORDS_BIGENDIAN	if (IS_TDS7_PLUS(tds)) {		/* TDS 7/8 only supports little endian */		tds->emul_little_endian = 1;	}#endif	/* set up iconv if not already initialized*/	if (tds->char_convs[client2ucs2]->to_wire == (iconv_t) -1) {		if (!tds_dstr_isempty(&connection->client_charset)) {			tds_iconv_open(tds, tds_dstr_cstr(&connection->client_charset));		}	}	/* specified a date format? */	/*	 * if (connection->date_fmt) {	 * tds->date_fmt=strdup(connection->date_fmt);	 * }	 */	connect_timeout = connection->connect_timeout;	/* Jeff's hack - begin */	tds->query_timeout = connect_timeout ? connect_timeout : connection->query_timeout;	/* end */	/* verify that ip_addr is not empty */	if (tds_dstr_isempty(&connection->ip_addr)) {		tdsdump_log(TDS_DBG_ERROR, "IP address pointer is empty\n");		if (!tds_dstr_isempty(&connection->server_name)) {			tdsdump_log(TDS_DBG_ERROR, "Server %s not found!\n", tds_dstr_cstr(&connection->server_name));		} else {			tdsdump_log(TDS_DBG_ERROR, "No server specified!\n");		}		return TDS_FAIL;	}	if (!IS_TDS50(tds) && !tds_dstr_isempty(&connection->instance_name))		connection->port = tds7_get_instance_port(tds_dstr_cstr(&connection->ip_addr), tds_dstr_cstr(&connection->instance_name));	if (connection->port < 1) {		tdsdump_log(TDS_DBG_ERROR, "invalid port number\n");		return TDS_FAIL;	}	memcpy(tds->capabilities, connection->capabilities, TDS_MAX_CAPABILITY);	retval = tds_version(tds, version);	if (!retval)		version[0] = '\0';	if (tds_open_socket(tds, tds_dstr_cstr(&connection->ip_addr), connection->port, connect_timeout) != TDS_SUCCEED)		return TDS_FAIL;	tds_set_state(tds, TDS_IDLE);	if (IS_TDS8_PLUS(tds)) {		retval = tds8_do_login(tds, connection);		db_selected = 1;	} else if (IS_TDS7_PLUS(tds)) {		retval = tds7_send_login(tds, connection);		db_selected = 1;	} else {		tds->out_flag = TDS_LOGIN;		retval = tds_send_login(tds, connection);	}	if (retval == TDS_FAIL || !tds_process_login_tokens(tds)) {		tds_close_socket(tds);		tdserror(tds->tds_ctx, tds, TDSEFCON, 0); 	/* "Adaptive Server connection failed" */								/* If it's a bad login, the server will send that mesasge */		return TDS_FAIL;	}	if (connection->text_size || (!db_selected && !tds_dstr_isempty(&connection->database))) {		len = 64 + tds_quote_id(tds, NULL, tds_dstr_cstr(&connection->database),-1);		if ((str = (char *) malloc(len)) == NULL)			return TDS_FAIL;		str[0] = 0;		if (connection->text_size) {			sprintf(str, "set textsize %d ", connection->text_size);		}		if (!db_selected && !tds_dstr_isempty(&connection->database)) {			strcat(str, "use ");			tds_quote_id(tds, strchr(str, 0), tds_dstr_cstr(&connection->database), -1);		}		retval = tds_submit_query(tds, str);		free(str);		if (retval != TDS_SUCCEED)			return TDS_FAIL;		if (tds_process_simple_query(tds) != TDS_SUCCEED)			return TDS_FAIL;	}	tds->query_timeout = connection->query_timeout;	tds->connection = NULL;	return TDS_SUCCEED;}static inttds_put_login_string(TDSSOCKET * tds, const char *buf, int n){	int buf_len = (buf ? strlen(buf) : 0);	return tds_put_buf(tds, (const unsigned char *) buf, n, buf_len);}static inttds_send_login(TDSSOCKET * tds, TDSCONNECTION * connection){#ifdef WORDS_BIGENDIAN	static const unsigned char be1[] = { 0x02, 0x00, 0x06, 0x04, 0x08, 0x01 };#endif	static const unsigned char le1[] = { 0x03, 0x01, 0x06, 0x0a, 0x09, 0x01 };	static const unsigned char magic2[] = { 0x00, 0x00 };	static const unsigned char magic3[] = { 0x00, 0x00, 0x00 };	/* these seem to endian flags as well 13,17 on intel/alpha 12,16 on power */#ifdef WORDS_BIGENDIAN	static const unsigned char be2[] = { 0x00, 12, 16 };#endif	static const unsigned char le2[] = { 0x00, 13, 17 };	/* 	 * the former byte 0 of magic5 causes the language token and message to be 	 * absent from the login acknowledgement if set to 1. There must be a way 	 * of setting this in the client layer, but I am not aware of any thing of	 * the sort -- bsb 01/17/99	 */	static const unsigned char magic5[] = { 0x00, 0x00 };	static const unsigned char magic6[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };	static const unsigned char magic42[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };	static const unsigned char magic50[] = { 0x00, 0x00, 0x00, 0x00 };	/*	 * capabilities are now part of the tds structure.	 * unsigned char capabilities[]= {0x01,0x07,0x03,109,127,0xFF,0xFF,0xFF,0xFE,0x02,0x07,0x00,0x00,0x0A,104,0x00,0x00,0x00};

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?