Esempio n. 1
0
/**
 * Check the server name to find port info first
 * return 1 when found, else 0
 * Warning: connect_info-> & login-> are all modified when needed
 */
static int
parse_server_name_for_port(TDSCONNECTINFO * connect_info, TDSLOGIN * login)
{
	char *pSep, *pEnd;
	char *server;

	/* seek the ':' in login server_name */
	server = tds_dstr_cstr(&login->server_name);
	pEnd = server + strlen(server);
	for (pSep = server; pSep < pEnd; pSep++)
		if (*pSep == ':')
			break;

	if ((pSep < pEnd) && (pSep != server)) {	/* yes, i found it! */
		if (!tds_dstr_copyn(&connect_info->server_name, server, pSep - server))	/* end the server_name before the ':' */
			return 0;	/* FALSE */

		/* modify connect_info-> && login->server_name & ->port */
		login->port = connect_info->port = atoi(pSep + 1);
		*pSep = 0;

		/* connect_info->ip_addr needed */
		{
			char tmp[256];

			tds_lookup_host(tds_dstr_cstr(&connect_info->server_name), tmp);
			if (!tds_dstr_copy(&connect_info->ip_addr, tmp))
				return 0;	/* FALSE */
		}

		return 1;	/* TRUE */
	} else
		return 0;	/* FALSE */
}
Esempio n. 2
0
/**
 * Handle conversions from TDS (N)CHAR to ODBC (W)CHAR
 */
static SQLLEN
odbc_convert_char(TDS_STMT * stmt, TDSCOLUMN * curcol, TDS_CHAR * src, TDS_UINT srclen, int desttype, TDS_CHAR * dest, SQLULEN destlen)
{
	const char *ib;
	char *ob;
	size_t il, ol, char_size;

	/* FIXME MARS not correct cause is the global tds but stmt->tds can be NULL on SQLGetData */
	TDSSOCKET *tds = stmt->dbc->tds_socket;

	TDSICONV *conv = curcol->char_conv;
	if (!conv)
		conv = tds->conn->char_convs[client2server_chardata];
	if (desttype == SQL_C_WCHAR) {
		/* SQL_C_WCHAR, convert to wide encode */
		conv = tds_iconv_get(tds->conn, ODBC_WIDE_NAME, conv->to.charset.name);
		if (!conv)
			conv = tds_iconv_get(tds->conn, ODBC_WIDE_NAME, "ISO-8859-1");
#ifdef ENABLE_ODBC_WIDE
	} else {
		conv = tds_iconv_get(tds->conn, tds_dstr_cstr(&stmt->dbc->original_charset), conv->to.charset.name);
		if (!conv)
			conv = tds_iconv_get(tds->conn, tds_dstr_cstr(&stmt->dbc->original_charset), "ISO-8859-1");
		if (!conv)
			conv = tds_iconv_get(tds->conn, "ISO-8859-1", "ISO-8859-1");
#endif
	}

	ib = src;
	il = srclen;
	ob = dest;
	ol = 0;
	char_size = desttype == SQL_C_CHAR ? 1 : SIZEOF_SQLWCHAR;
	if (destlen >= char_size) {
		ol = destlen - char_size;
		memset(&conv->suppress, 0, sizeof(conv->suppress));
		conv->suppress.e2big = 1;
		/* TODO check return value */
		tds_iconv(tds, conv, to_client, &ib, &il, &ob, &ol);
		ol = ob - dest; /* bytes written */
		if (curcol)
			curcol->column_text_sqlgetdatapos += ib - src;
		/* terminate string */
		memset(ob, 0, char_size);
	}

	/* returned size have to take into account buffer left unconverted */
	if (il == 0 || (conv->from.charset.min_bytes_per_char == conv->from.charset.max_bytes_per_char
	    && conv->to.charset.min_bytes_per_char == conv->to.charset.max_bytes_per_char)) {
		ol += il * conv->from.charset.min_bytes_per_char / conv->to.charset.min_bytes_per_char;
	} else {
		/* TODO convert and discard ?? or return proper SQL_NO_TOTAL values ?? */
		return SQL_NO_TOTAL;
	}
	return ol;
}
Esempio n. 3
0
void
tds7_send_result(TDSSOCKET * tds, TDSRESULTINFO * resinfo)
{
	int i, j;
	TDSCOLUMN *curcol;

	/* TDS7+ uses TDS7_RESULT_TOKEN to send column names and info */
	tds_put_byte(tds, TDS7_RESULT_TOKEN);

	/* send the number of columns */
	tds_put_smallint(tds, resinfo->num_cols);

	/* send info about each column */
	for (i = 0; i < resinfo->num_cols; i++) {

		/* usertype, flags, and type */
		curcol = resinfo->columns[i];
		tds_put_smallint(tds, curcol->column_usertype);
		tds_put_smallint(tds, curcol->column_flags);
		tds_put_byte(tds, curcol->column_type); /* smallint? */

		/* bytes in "size" field varies */
		if (is_blob_type(curcol->column_type)) {
			tds_put_int(tds, curcol->column_size);
		} else if (curcol->column_type>=128) { /*is_large_type*/
			tds_put_smallint(tds, curcol->column_size);
		} else {
			tds_put_tinyint(tds, curcol->column_size);
		}

		/* some types have extra info */
		if (is_numeric_type(curcol->column_type)) {
			tds_put_tinyint(tds, curcol->column_prec);
			tds_put_tinyint(tds, curcol->column_scale);
		} else if (is_blob_type(curcol->column_type)) {
			size_t len = tds_dstr_len(&curcol->table_name);
			const char *name = tds_dstr_cstr(&curcol->table_name);

			tds_put_smallint(tds, 2 * len);
			for (j = 0; name[j] != '\0'; j++){
				tds_put_byte(tds, name[j]);
				tds_put_byte(tds, 0);
			}
		}

		/* finally the name, in UCS16 format */
		tds_put_byte(tds, tds_dstr_len(&curcol->column_name));
		for (j = 0; j < tds_dstr_len(&curcol->column_name); j++) {
			tds_put_byte(tds, tds_dstr_cstr(&curcol->column_name)[j]);
			tds_put_byte(tds, 0);
		}
	}
}
Esempio n. 4
0
/**
 * tds_read_config_info() will fill the tds connect_info structure based on configuration 
 * information gathered in the following order:
 * 1) Program specified in TDSLOGIN structure
 * 2) The environment variables TDSVER, TDSDUMP, TDSPORT, TDSQUERY, TDSHOST
 * 3) A config file with the following search order:
 *    a) a readable file specified by environment variable FREETDSCONF
 *    b) a readable file in ~/.freetds.conf
 *    c) a readable file in $prefix/etc/freetds.conf
 * 3) ~/.interfaces if exists
 * 4) $SYBASE/interfaces if exists
 * 5) TDS_DEF_* default values
 *
 * .tdsrc and freetds.conf have been added to make the package easier to 
 * integration with various Linux and *BSD distributions.
 */
TDSCONNECTINFO *
tds_read_config_info(TDSSOCKET * tds, TDSLOGIN * login, TDSLOCALE * locale)
{
	TDSCONNECTINFO *connect_info;
	char *s;
	char *path;
	pid_t pid;
	int opened = 0;

	/* allocate a new structure with hard coded and build-time defaults */
	connect_info = tds_alloc_connect(locale);
	if (!connect_info)
		return NULL;

	s = getenv("TDSDUMPCONFIG");
	if (s) {
		if (*s) {
			opened = tdsdump_open(s);
		} else {
			pid = getpid();
			if (asprintf(&path, "/tmp/tdsconfig.log.%d", pid) >= 0) {
				if (*path) {
					opened = tdsdump_open(path);
				}
				free(path);
			}
		}
	}

	tdsdump_log(TDS_DBG_INFO1, "%L Attempting to read conf files.\n");
	if (!tds_read_conf_file(connect_info, tds_dstr_cstr(&login->server_name))) {
		/* fallback to interfaces file */
		tdsdump_log(TDS_DBG_INFO1, "%L Failed in reading conf file.  Trying interface files.\n");
		tds_read_interfaces(tds_dstr_cstr(&login->server_name), connect_info);
	}

	if (parse_server_name_for_port(connect_info, login)) {
		tdsdump_log(TDS_DBG_INFO1, "%L Parsed servername, now %s on %d.\n", connect_info->server_name, login->port);
	}

	tds_fix_connect(connect_info);

	/* And finally the login structure */
	tds_config_login(connect_info, login);

	if (opened) {
		tdsdump_close();
	}
	return connect_info;
}
Esempio n. 5
0
static BOOL
write_all_strings(DSNINFO * di)
{
	char odbcini[FILENAME_MAX];
	char tmp[100];
	const char *section = tds_dstr_cstr(&di->dsn);

	strcpy(odbcini, "odbc.ini");

	WRITESTR("Server", FIELD_STRING(server_name));
	WRITESTR("Language", FIELD_STRING(language));
	WRITESTR("Database", FIELD_STRING(database));

	sprintf(tmp, "%u", di->login->port);
	WRITESTR("Port", tmp);

	sprintf(tmp, "%d.%d", TDS_MAJOR(di->login), TDS_MINOR(di->login));
	WRITESTR("TDS_Version", tmp);

	sprintf(tmp, "%u", di->login->text_size);
	WRITESTR("TextSize", tmp);

	sprintf(tmp, "%u", di->login->block_size);
	WRITESTR("PacketSize", tmp);

	return TRUE;
}
Esempio n. 6
0
void
tds_send_result(TDSSOCKET * tds, TDSRESULTINFO * resinfo)
{
	TDSCOLUMN *curcol;
	int i, totlen;
	size_t len;

	tds_put_byte(tds, TDS_RESULT_TOKEN);
	totlen = 2;
	for (i = 0; i < resinfo->num_cols; i++) {
		curcol = resinfo->columns[i];
		len = tds_dstr_len(&curcol->column_name);
		totlen += 8;
		totlen += len;
		curcol = resinfo->columns[i];
		if (!is_fixed_type(curcol->column_type)) {
			totlen++;
		}
	}
	tds_put_smallint(tds, totlen);
	tds_put_smallint(tds, resinfo->num_cols);
	for (i = 0; i < resinfo->num_cols; i++) {
		curcol = resinfo->columns[i];
		len = tds_dstr_len(&curcol->column_name);
		tds_put_byte(tds, tds_dstr_len(&curcol->column_name));
		tds_put_n(tds, tds_dstr_cstr(&curcol->column_name), len);
		tds_put_byte(tds, '0');
		tds_put_int(tds, curcol->column_usertype);
		tds_put_byte(tds, curcol->column_type);
		if (!is_fixed_type(curcol->column_type)) {
			tds_put_byte(tds, curcol->column_size);
		}
		tds_put_byte(tds, 0);
	}
}
Esempio n. 7
0
static int
tds_read_conf_sections(FILE * in, const char *server, TDSLOGIN * login)
{
	DSTR default_instance;
	int default_port;

	int found;

	tds_read_conf_section(in, "global", tds_parse_conf_section, login);

	if (!server[0])
		return 0;
	rewind(in);

	tds_dstr_init(&default_instance);
	tds_dstr_dup(&default_instance, &login->instance_name);
	default_port = login->port;

	found = tds_read_conf_section(in, server, tds_parse_conf_section, login);

	/* 
	 * If both instance and port are specified and neither one came from the default, it's an error 
	 * TODO: If port/instance is specified in the non-default, it has priority over the default setting. 
	 * TODO: test this. 
	 */
	if (!tds_dstr_isempty(&login->instance_name) && login->port &&
	    !(!tds_dstr_isempty(&default_instance) || default_port)) {
		tdsdump_log(TDS_DBG_ERROR, "error: cannot specify both port %d and instance %s.\n", 
						login->port, tds_dstr_cstr(&login->instance_name));
		/* tdserror(tds_get_ctx(tds), tds, TDSEPORTINSTANCE, 0); */
	}
	tds_dstr_free(&default_instance);
	return found;
}
Esempio n. 8
0
static boolean
reinit_results(TDSSOCKET * tds, size_t num_cols, const struct metadata_t meta[])
{
	TDSRESULTINFO *info;
	int i;

	assert(tds);
	assert(num_cols);
	assert(meta);
	
	tds_free_all_results(tds);
	tds->rows_affected = TDS_NO_COUNT;

	if ((info = alloc_results(num_cols)) == NULL)
		return false;

	tds_set_current_results(tds, info);
	if (tds->cur_cursor) {
		tds_free_results(tds->cur_cursor->res_info);
		tds->cur_cursor->res_info = info;
		tdsdump_log(TDS_DBG_INFO1, "set current_results to cursor->res_info\n");
	} else {
		tds->res_info = info;
		tdsdump_log(TDS_DBG_INFO1, "set current_results (%u column%s) to tds->res_info\n", (unsigned) num_cols, (num_cols==1? "":"s"));
	}

	tdsdump_log(TDS_DBG_INFO1, "setting up %u columns\n", (unsigned) num_cols);
	
	for (i = 0; i < num_cols; i++) {
		set_result_column(tds, info->columns[i], meta[i].name, &meta[i].col);
		info->columns[i]->bcp_terminator = (char*) meta[i].pacross;	/* overload available pointer */
	}
		
	if (num_cols > 0) {
		static char dashes[31] = "------------------------------";
		tdsdump_log(TDS_DBG_INFO1, " %-20s %-15s %-15s %-7s\n", "name", "size/wsize", "type/wtype", "utype");
		tdsdump_log(TDS_DBG_INFO1, " %-20s %15s %15s %7s\n", dashes+10, dashes+30-15, dashes+30-15, dashes+30-7);
	}
	for (i = 0; i < num_cols; i++) {
		TDSCOLUMN *curcol = info->columns[i];

		tdsdump_log(TDS_DBG_INFO1, " %-20s %7d/%-7d %7d/%-7d %7d\n", 
						tds_dstr_cstr(&curcol->column_name),
						curcol->column_size, curcol->on_server.column_size, 
						curcol->column_type, curcol->on_server.column_type, 
						curcol->column_usertype);
	}

#if 1
	/* all done now allocate a row for tds_process_row to use */
	if (TDS_FAILED(tds_alloc_row(info))) return false;
#endif
	return true;
}
Esempio n. 9
0
/**
 * Help to build query to be sent to server.
 * Append column declaration to the query.
 * Only for TDS 7.0+.
 * \tds
 * \param[out] clause output string
 * \param bcpcol column to append
 * \param first  true if column is the first
 * \return TDS_SUCCESS or TDS_FAIL.
 */
static TDSRET
tds7_build_bulk_insert_stmt(TDSSOCKET * tds, TDSPBCB * clause, TDSCOLUMN * bcpcol, int first)
{
	char column_type[40];

	tdsdump_log(TDS_DBG_FUNC, "tds7_build_bulk_insert_stmt(%p, %p, %p, %d)\n", tds, clause, bcpcol, first);

	if (TDS_FAILED(tds_get_column_declaration(tds, bcpcol, column_type))) {
		tdserror(tds_get_ctx(tds), tds, TDSEBPROBADTYP, errno);
		tdsdump_log(TDS_DBG_FUNC, "error: cannot build bulk insert statement. unrecognized server datatype %d\n",
			    bcpcol->on_server.column_type);
		return TDS_FAIL;
	}

	if (clause->cb < strlen(clause->pb)
	    + tds_quote_id(tds, NULL, tds_dstr_cstr(&bcpcol->column_name), tds_dstr_len(&bcpcol->column_name))
	    + strlen(column_type)
	    + ((first) ? 2u : 4u)) {
		char *temp = (char*) malloc(2 * clause->cb);

		if (!temp) {
			tdserror(tds_get_ctx(tds), tds, TDSEMEM, errno);
			return TDS_FAIL;
		}
		strcpy(temp, clause->pb);
		if (clause->from_malloc)
			free(clause->pb);
		clause->from_malloc = 1;
		clause->pb = temp;
		clause->cb *= 2;
	}

	if (!first)
		strcat(clause->pb, ", ");

	tds_quote_id(tds, strchr(clause->pb, 0), tds_dstr_cstr(&bcpcol->column_name), tds_dstr_len(&bcpcol->column_name));
	strcat(clause->pb, " ");
	strcat(clause->pb, column_type);

	return TDS_SUCCESS;
}
Esempio n. 10
0
void
dump_login(TDSLOGIN * login)
{
	fprintf(stderr, "host %s\n", tds_dstr_cstr(&login->client_host_name));
	fprintf(stderr, "user %s\n", tds_dstr_cstr(&login->user_name));
	fprintf(stderr, "pass %s\n", tds_dstr_cstr(&login->password));
	fprintf(stderr, "app  %s\n", tds_dstr_cstr(&login->app_name));
	fprintf(stderr, "srvr %s\n", tds_dstr_cstr(&login->server_name));
	fprintf(stderr, "vers %d.%d\n", TDS_MAJOR(login), TDS_MINOR(login));
	fprintf(stderr, "lib  %s\n", tds_dstr_cstr(&login->library));
	fprintf(stderr, "lang %s\n", tds_dstr_cstr(&login->language));
	fprintf(stderr, "char %s\n", tds_dstr_cstr(&login->server_charset));
	fprintf(stderr, "bsiz %d\n", login->block_size);
}
Esempio n. 11
0
static void
dump_login(TDSLOGIN * login)
{
    printf("host %s\n", tds_dstr_cstr(&login->client_host_name));
    printf("user %s\n", tds_dstr_cstr(&login->user_name));
    printf("pass %s\n", tds_dstr_cstr(&login->password));
    printf("app  %s\n", tds_dstr_cstr(&login->app_name));
    printf("srvr %s\n", tds_dstr_cstr(&login->server_name));
    printf("vers %d.%d\n", login->major_version, login->minor_version);
    printf("lib  %s\n", tds_dstr_cstr(&login->library));
    printf("lang %s\n", tds_dstr_cstr(&login->language));
    printf("char %s\n", tds_dstr_cstr(&login->server_charset));
    printf("bsiz %d\n", login->block_size);
}
Esempio n. 12
0
/**
 * Go looking for trouble.  Return NULL if the info is okay, or an error message
 * if something needs to change.
 */
static const char *
validate(DSNINFO * di)
{
	if (!SQLValidDSN(tds_dstr_cstr(&di->dsn)))
		return "Invalid DSN";
	if (!IS_TDS42(di->login) && !IS_TDS46(di->login)
	    && !IS_TDS50(di->login) && !IS_TDS7_PLUS(di->login))
		return "Bad Protocol version";
	if (tds_dstr_isempty(&di->login->server_name))
		return "Address is required";
	if (di->login->port < 1 || di->login->port > 65535)
		return "Bad port - Try 1433 or 4000";
	return NULL;
}
Esempio n. 13
0
static void
tds_config_env_tdsdump(TDSLOGIN * login)
{
	char *s;
	char *path;
	pid_t pid = 0;

	if ((s = getenv("TDSDUMP"))) {
		if (!strlen(s)) {
			pid = getpid();
			if (asprintf(&path, pid_logpath, pid) >= 0)
				tds_dstr_set(&login->dump_file, path);
		} else {
			tds_dstr_copy(&login->dump_file, s);
		}
		tdsdump_log(TDS_DBG_INFO1, "Setting 'dump_file' to '%s' from $TDSDUMP.\n", tds_dstr_cstr(&login->dump_file));
	}
}
Esempio n. 14
0
void
tds_send_col_name(TDSSOCKET * tds, TDSRESULTINFO * resinfo)
{
	int col, hdrsize = 0;
	TDSCOLUMN *curcol;

	tds_put_byte(tds, TDS_COLNAME_TOKEN);
	for (col = 0; col < resinfo->num_cols; col++) {
		curcol = resinfo->columns[col];
		hdrsize += tds_dstr_len(&curcol->column_name) + 1;
	}

	tds_put_smallint(tds, hdrsize);
	for (col = 0; col < resinfo->num_cols; col++) {
		curcol = resinfo->columns[col];
		tds_put_byte(tds, tds_dstr_len(&curcol->column_name));
		/* exclude the null */
		tds_put_n(tds, tds_dstr_cstr(&curcol->column_name), tds_dstr_len(&curcol->column_name));
	}
}
Esempio n. 15
0
/**
 * Check the server name to find port info first
 * Warning: connection-> & login-> are all modified when needed
 * \return 1 when found, else 0
 */
static int
parse_server_name_for_port(TDSLOGIN * connection, TDSLOGIN * login)
{
	const char *pSep;
	const char *server;

	/* seek the ':' in login server_name */
	server = tds_dstr_cstr(&login->server_name);

	/* IPv6 address can be quoted */
	if (server[0] == '[') {
		pSep = strstr(server, "]:");
		if (pSep)
			++pSep;
	} else {
		pSep = strrchr(server, ':');
	}

	if (pSep && pSep != server) {	/* yes, i found it! */
		/* modify connection-> && login->server_name & ->port */
		login->port = connection->port = atoi(pSep + 1);
		tds_dstr_empty(&connection->instance_name);
	} else {
		/* handle instance name */
		pSep = strrchr(server, '\\');
		if (!pSep || pSep == server)
			return 0;

		if (!tds_dstr_copy(&connection->instance_name, pSep + 1))
			return 0;
		connection->port = 0;
	}

	if (!tds_dstr_copyn(&connection->server_name, server, pSep - server))
		return 0;

	return 1;
}
Esempio n. 16
0
static TDSRET
set_result_column(TDSSOCKET * tds, TDSCOLUMN * curcol, const char name[], const struct col_t *pvalue)
{
	assert(curcol && pvalue);
	assert(name);

	curcol->column_usertype = pvalue->type;
	curcol->column_nullable = true;
	curcol->column_writeable = false;
	curcol->column_identity = false;

	tds_set_column_type(tds->conn, curcol, pvalue->type);	/* sets "cardinal" type */

	curcol->column_timestamp = (curcol->column_type == SYBBINARY && curcol->column_usertype == TDS_UT_TIMESTAMP);

#if 0
	curcol->funcs->get_info(tds, curcol);
#endif
	curcol->on_server.column_size = curcol->column_size;

	if (!tds_dstr_copy(&curcol->column_name, name))
		return TDS_FAIL;

	tdsdump_log(TDS_DBG_INFO1, "tds7_get_data_info: \n"
		    "\tcolname = %s\n"
		    "\ttype = %d (%s)\n"
		    "\tserver's type = %d (%s)\n"
		    "\tcolumn_varint_size = %d\n"
		    "\tcolumn_size = %d (%d on server)\n",
		    tds_dstr_cstr(&curcol->column_name),
		    curcol->column_type, tds_prtype(curcol->column_type), 
		    curcol->on_server.column_type, tds_prtype(curcol->on_server.column_type), 
		    curcol->column_varint_size,
		    curcol->column_size, curcol->on_server.column_size);

	return TDS_SUCCESS;
}
Esempio n. 17
0
void
odbc_check_stmt_extra(TDS_STMT * stmt)
{
	assert(stmt && stmt->htype == SQL_HANDLE_STMT);
	/* TODO deep check on connection */
	assert(stmt->dbc);
	odbc_check_desc_extra(stmt->ard);
	odbc_check_desc_extra(stmt->ird);
	odbc_check_desc_extra(stmt->apd);
	odbc_check_desc_extra(stmt->ipd);
	assert(!stmt->prepared_query_is_func || stmt->prepared_query_is_rpc);
	assert(stmt->param_num <= stmt->param_count + 1);
	assert(stmt->num_param_rows >= 1);
	assert(stmt->curr_param_row >= 0);
	assert(stmt->curr_param_row <= stmt->num_param_rows);
	if (stmt->prepared_query_is_rpc) {
		const char *query = tds_dstr_cstr(&stmt->query);
		assert(query);
		assert(stmt->prepared_pos == NULL || (stmt->prepared_pos >= query && stmt->prepared_pos <= strchr(query,0)));
	} else {
		assert(stmt->prepared_pos == NULL);
	}
	/* TODO assert dbc has this statement in list */
}
Esempio n. 18
0
static int
tds_config_login(TDSLOGIN * connection, TDSLOGIN * login)
{
	DSTR *res = &login->server_name;

	if (!tds_dstr_isempty(&login->server_name)) {
		if (1 || tds_dstr_isempty(&connection->server_name)) 
			res = tds_dstr_dup(&connection->server_name, &login->server_name);
	}
	if (login->tds_version)
		connection->tds_version = login->tds_version;
	if (res && !tds_dstr_isempty(&login->language)) {
		res = tds_dstr_dup(&connection->language, &login->language);
	}
	if (res && !tds_dstr_isempty(&login->server_charset)) {
		res = tds_dstr_dup(&connection->server_charset, &login->server_charset);
	}
	if (res && !tds_dstr_isempty(&login->client_charset)) {
		res = tds_dstr_dup(&connection->client_charset, &login->client_charset);
		tdsdump_log(TDS_DBG_INFO1, "tds_config_login: %s is %s.\n", "client_charset",
			    tds_dstr_cstr(&connection->client_charset));
	}
	if (!login->use_utf16)
		connection->use_utf16 = login->use_utf16;
	if (res && !tds_dstr_isempty(&login->database)) {
		res = tds_dstr_dup(&connection->database, &login->database);
		tdsdump_log(TDS_DBG_INFO1, "tds_config_login: %s is %s.\n", "database_name",
			    tds_dstr_cstr(&connection->database));
	}
	if (res && !tds_dstr_isempty(&login->client_host_name)) {
		res = tds_dstr_dup(&connection->client_host_name, &login->client_host_name);
	}
	if (res && !tds_dstr_isempty(&login->app_name)) {
		res = tds_dstr_dup(&connection->app_name, &login->app_name);
	}
	if (res && !tds_dstr_isempty(&login->user_name)) {
		res = tds_dstr_dup(&connection->user_name, &login->user_name);
	}
	if (res && !tds_dstr_isempty(&login->password)) {
		/* for security reason clear memory */
		tds_dstr_zero(&connection->password);
		res = tds_dstr_dup(&connection->password, &login->password);
	}
	if (res && !tds_dstr_isempty(&login->library)) {
		res = tds_dstr_dup(&connection->library, &login->library);
	}
	if (login->encryption_level) {
		connection->encryption_level = login->encryption_level;
	}
	if (login->suppress_language) {
		connection->suppress_language = 1;
	}
	if (login->bulk_copy) {
		connection->bulk_copy = 1;
	}
	if (login->block_size) {
		connection->block_size = login->block_size;
	}
	if (login->port)
		connection->port = login->port;
	if (login->connect_timeout)
		connection->connect_timeout = login->connect_timeout;

	if (login->query_timeout)
		connection->query_timeout = login->query_timeout;

	if (!login->check_ssl_hostname)
		connection->check_ssl_hostname = login->check_ssl_hostname;

	if (res && !tds_dstr_isempty(&login->db_filename)) {
		res = tds_dstr_dup(&connection->db_filename, &login->db_filename);
	}

	/* copy other info not present in configuration file */
	connection->capabilities = login->capabilities;

	if (login->readonly_intent)
		connection->readonly_intent = login->readonly_intent;
	connection->use_new_password = login->use_new_password;
	if (res)
		res = tds_dstr_dup(&connection->new_password, &login->new_password);

	return res != NULL;
}
Esempio n. 19
0
static int
tds_verify_certificate(gnutls_session_t session)
{
	unsigned int status;
	int ret;
	TDSSOCKET *tds = (TDSSOCKET *) gnutls_transport_get_ptr(session);

#ifdef ENABLE_DEVELOPING
	unsigned int list_size;
	const gnutls_datum_t *cert_list;
#endif

	if (!tds->login)
		return GNUTLS_E_CERTIFICATE_ERROR;

	ret = gnutls_certificate_verify_peers2(session, &status);
	if (ret < 0) {
		tdsdump_log(TDS_DBG_ERROR, "Error verifying certificate: %s\n", gnutls_strerror(ret));
		return GNUTLS_E_CERTIFICATE_ERROR;
	}

#ifdef ENABLE_DEVELOPING
	cert_list = gnutls_certificate_get_peers(session, &list_size);
	if (cert_list) {
		gnutls_x509_crt_t cert;
		gnutls_datum_t cinfo;
		char buf[8192];
		size_t size;

		gnutls_x509_crt_init(&cert);

		gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);

		/* This is the preferred way of printing short information about
		 * a certificate. */
		size = sizeof(buf);
		ret = gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_PEM, buf, &size);
		if (ret == 0) {
			FILE *f = fopen("cert.dat", "wb");
			if (f) {
				fwrite(buf, size, 1, f);
				fclose(f);
			}
		}

		ret = gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_ONELINE, &cinfo);
		if (ret == 0) {
			tdsdump_log(TDS_DBG_INFO1, "Certificate info: %s\n", cinfo.data);
			gnutls_free(cinfo.data);
		}

		gnutls_x509_crt_deinit(cert);
	}
#endif

	/* Certificate is not trusted */
	if (status != 0) {
		tdsdump_log(TDS_DBG_ERROR, "Certificate status: %u\n", status);
		return GNUTLS_E_CERTIFICATE_ERROR;
	}

	/* check hostname */
	if (tds->login->check_ssl_hostname) {
		const gnutls_datum_t *cert_list;
		unsigned int list_size;
		gnutls_x509_crt_t cert;

		cert_list = gnutls_certificate_get_peers(session, &list_size);
		if (!cert_list) {
			tdsdump_log(TDS_DBG_ERROR, "Error getting TLS session peers\n");
			return GNUTLS_E_CERTIFICATE_ERROR;
		}
		gnutls_x509_crt_init(&cert);
		gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
		ret = gnutls_x509_crt_check_hostname(cert, tds_dstr_cstr(&tds->login->server_host_name));
		gnutls_x509_crt_deinit(cert);
		if (!ret) {
			tdsdump_log(TDS_DBG_ERROR, "Certificate hostname does not match\n");
			return GNUTLS_E_CERTIFICATE_ERROR;
		}
	}

	/* notify gnutls to continue handshake normally */
	return 0;
}
Esempio n. 20
0
/**
 * tds_read_config_info() will fill the tds connection structure based on configuration 
 * information gathered in the following order:
 * 1) Program specified in TDSLOGIN structure
 * 2) The environment variables TDSVER, TDSDUMP, TDSPORT, TDSQUERY, TDSHOST
 * 3) A config file with the following search order:
 *    a) a readable file specified by environment variable FREETDSCONF
 *    b) a readable file in ~/.freetds.conf
 *    c) a readable file in $prefix/etc/freetds.conf
 * 3) ~/.interfaces if exists
 * 4) $SYBASE/interfaces if exists
 * 5) TDS_DEF_* default values
 *
 * .tdsrc and freetds.conf have been added to make the package easier to 
 * integration with various Linux and *BSD distributions.
 */
TDSLOGIN *
tds_read_config_info(TDSSOCKET * tds, TDSLOGIN * login, TDSLOCALE * locale)
{
	TDSLOGIN *connection;
	char *s;
	char *path;
	pid_t pid;
	int opened = 0, found;
	struct addrinfo *addrs;

	/* allocate a new structure with hard coded and build-time defaults */
	connection = tds_alloc_login(0);
	if (!connection || !tds_init_login(connection, locale)) {
		tds_free_login(connection);
		return NULL;
	}

	s = getenv("TDSDUMPCONFIG");
	if (s) {
		if (*s) {
			opened = tdsdump_open(s);
		} else {
			pid = getpid();
			if (asprintf(&path, pid_config_logpath, pid) >= 0) {
				if (*path) {
					opened = tdsdump_open(path);
				}
				free(path);
			}
		}
	}

	tdsdump_log(TDS_DBG_INFO1, "Getting connection information for [%s].\n", 
			    tds_dstr_cstr(&login->server_name));	/* (The server name is set in login.c.) */

	/* Read the config files. */
	tdsdump_log(TDS_DBG_INFO1, "Attempting to read conf files.\n");
	found = tds_read_conf_file(connection, tds_dstr_cstr(&login->server_name));
	if (!found) {
		if (parse_server_name_for_port(connection, login)) {

			found = tds_read_conf_file(connection, tds_dstr_cstr(&connection->server_name));
			/* do it again to really override what found in freetds.conf */
			if (found) {
				parse_server_name_for_port(connection, login);
			} else if (TDS_SUCCEED(tds_lookup_host_set(tds_dstr_cstr(&connection->server_name), &connection->ip_addrs))) {
				if (!tds_dstr_dup(&connection->server_host_name, &connection->server_name)) {
					tds_free_login(connection);
					return NULL;
				}
				found = 1;
			}
		}
	}
	if (!found) {
		/* fallback to interfaces file */
		tdsdump_log(TDS_DBG_INFO1, "Failed in reading conf file.  Trying interface files.\n");
		if (!tds_read_interfaces(tds_dstr_cstr(&login->server_name), connection)) {
			tdsdump_log(TDS_DBG_INFO1, "Failed to find [%s] in configuration files; trying '%s' instead.\n", 
						   tds_dstr_cstr(&login->server_name), tds_dstr_cstr(&connection->server_name));
			if (connection->ip_addrs == NULL)
				tdserror(tds_get_ctx(tds), tds, TDSEINTF, 0);
		}
	}

	/* Override config file settings with environment variables. */
	tds_fix_login(connection);

	/* And finally apply anything from the login structure */
	if (!tds_config_login(connection, login)) {
		tds_free_login(connection);
		return NULL;
	}
	
	if (opened) {
		char tmp[128];

		tdsdump_log(TDS_DBG_INFO1, "Final connection parameters:\n");
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "server_name", tds_dstr_cstr(&connection->server_name));
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "server_host_name", tds_dstr_cstr(&connection->server_host_name));

		for (addrs = connection->ip_addrs; addrs != NULL; addrs = addrs->ai_next)
			tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "ip_addr", tds_addrinfo2str(addrs, tmp, sizeof(tmp)));

		if (connection->ip_addrs == NULL)
			tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "ip_addr", "");

		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "instance_name", tds_dstr_cstr(&connection->instance_name));
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %d\n", "port", connection->port);
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %d\n", "major_version", TDS_MAJOR(connection));
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %d\n", "minor_version", TDS_MINOR(connection));
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %d\n", "block_size", connection->block_size);
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "language", tds_dstr_cstr(&connection->language));
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "server_charset", tds_dstr_cstr(&connection->server_charset));
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %d\n", "connect_timeout", connection->connect_timeout);
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "client_host_name", tds_dstr_cstr(&connection->client_host_name));
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "client_charset", tds_dstr_cstr(&connection->client_charset));
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %d\n", "use_utf16", connection->use_utf16);
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "app_name", tds_dstr_cstr(&connection->app_name));
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "user_name", tds_dstr_cstr(&connection->user_name));
		/* tdsdump_log(TDS_DBG_PASSWD, "\t%20s = %s\n", "password", tds_dstr_cstr(&connection->password)); 
			(no such flag yet) */
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "library", tds_dstr_cstr(&connection->library));
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %d\n", "bulk_copy", (int)connection->bulk_copy);
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %d\n", "suppress_language", (int)connection->suppress_language);
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %d\n", "encrypt level", (int)connection->encryption_level);
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %d\n", "query_timeout", connection->query_timeout);
		/* tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "capabilities", tds_dstr_cstr(&connection->capabilities)); 
			(not null terminated) */
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "database", tds_dstr_cstr(&connection->database));
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "dump_file", tds_dstr_cstr(&connection->dump_file));
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %x\n", "debug_flags", connection->debug_flags);
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %d\n", "text_size", connection->text_size);
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %d\n", "emul_little_endian", connection->emul_little_endian);
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "server_realm_name", tds_dstr_cstr(&connection->server_realm_name));
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "server_spn", tds_dstr_cstr(&connection->server_spn));
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "cafile", tds_dstr_cstr(&connection->cafile));
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "crlfile", tds_dstr_cstr(&connection->crlfile));
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %d\n", "check_ssl_hostname", connection->check_ssl_hostname);
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %s\n", "db_filename", tds_dstr_cstr(&connection->db_filename));
		tdsdump_log(TDS_DBG_INFO1, "\t%20s = %d\n", "readonly_intent", connection->readonly_intent);

		tdsdump_close();
	}

	/*
	 * If a dump file has been specified, start logging
	 */
	if (!tds_dstr_isempty(&connection->dump_file) && !tdsdump_isopen()) {
		if (connection->debug_flags)
			tds_debug_flags = connection->debug_flags;
		tdsdump_open(tds_dstr_cstr(&connection->dump_file));
	}

	return connection;
}
Esempio n. 21
0
/* Also used to scan ODBC.INI entries */
void
tds_parse_conf_section(const char *option, const char *value, void *param)
{
	TDSLOGIN *login = (TDSLOGIN *) param;
	void *s = param;

	tdsdump_log(TDS_DBG_INFO1, "\t%s = '%s'\n", option, value);

	if (!strcmp(option, TDS_STR_VERSION)) {
		tds_config_verstr(value, login);
	} else if (!strcmp(option, TDS_STR_BLKSZ)) {
		int val = atoi(value);
		if (val >= 512 && val < 65536)
			login->block_size = val;
	} else if (!strcmp(option, TDS_STR_SWAPDT)) {
		/* this option is deprecated, just check value for compatibility */
		tds_config_boolean(option, value, login);
	} else if (!strcmp(option, TDS_GSSAPI_DELEGATION)) {
		/* gssapi flag addition */
		login->gssapi_use_delegation = tds_config_boolean(option, value, login);
	} else if (!strcmp(option, TDS_STR_DUMPFILE)) {
		s = tds_dstr_copy(&login->dump_file, value);
	} else if (!strcmp(option, TDS_STR_DEBUGFLAGS)) {
		char *end;
		long flags;
		flags = strtol(value, &end, 0);
		if (*value != '\0' && *end == '\0' && flags != LONG_MIN && flags != LONG_MAX)
			login->debug_flags = flags;
	} else if (!strcmp(option, TDS_STR_TIMEOUT) || !strcmp(option, TDS_STR_QUERY_TIMEOUT)) {
		if (atoi(value))
			login->query_timeout = atoi(value);
	} else if (!strcmp(option, TDS_STR_CONNTIMEOUT)) {
		if (atoi(value))
			login->connect_timeout = atoi(value);
	} else if (!strcmp(option, TDS_STR_HOST)) {
		char tmp[128];
		struct addrinfo *addrs;

		if (TDS_FAILED(tds_lookup_host_set(value, &login->ip_addrs))) {
			tdsdump_log(TDS_DBG_WARN, "Found host entry %s however name resolution failed. \n", value);
			return;
		}

		tdsdump_log(TDS_DBG_INFO1, "Found host entry %s \n", value);
		s = tds_dstr_copy(&login->server_host_name, value);
		for (addrs = login->ip_addrs; addrs != NULL; addrs = addrs->ai_next)
			tdsdump_log(TDS_DBG_INFO1, "IP addr is %s.\n", tds_addrinfo2str(addrs, tmp, sizeof(tmp)));

	} else if (!strcmp(option, TDS_STR_PORT)) {
		if (atoi(value))
			login->port = atoi(value);
	} else if (!strcmp(option, TDS_STR_EMUL_LE)) {
		login->emul_little_endian = tds_config_boolean(option, value, login);
	} else if (!strcmp(option, TDS_STR_TEXTSZ)) {
		if (atoi(value))
			login->text_size = atoi(value);
	} else if (!strcmp(option, TDS_STR_CHARSET)) {
		s = tds_dstr_copy(&login->server_charset, value);
		tdsdump_log(TDS_DBG_INFO1, "%s is %s.\n", option, tds_dstr_cstr(&login->server_charset));
	} else if (!strcmp(option, TDS_STR_CLCHARSET)) {
		s = tds_dstr_copy(&login->client_charset, value);
		tdsdump_log(TDS_DBG_INFO1, "tds_parse_conf_section: %s is %s.\n", option, tds_dstr_cstr(&login->client_charset));
	} else if (!strcmp(option, TDS_STR_USE_UTF_16)) {
		login->use_utf16 = tds_config_boolean(option, value, login);
	} else if (!strcmp(option, TDS_STR_LANGUAGE)) {
		s = tds_dstr_copy(&login->language, value);
	} else if (!strcmp(option, TDS_STR_APPENDMODE)) {
		tds_g_append_mode = tds_config_boolean(option, value, login);
	} else if (!strcmp(option, TDS_STR_INSTANCE)) {
		s = tds_dstr_copy(&login->instance_name, value);
	} else if (!strcmp(option, TDS_STR_ENCRYPTION)) {
		tds_config_encryption(value, login);
	} else if (!strcmp(option, TDS_STR_ASA_DATABASE)) {
		s = tds_dstr_copy(&login->server_name, value);
	} else if (!strcmp(option, TDS_STR_USENTLMV2)) {
		login->use_ntlmv2 = tds_config_boolean(option, value, login);
	} else if (!strcmp(option, TDS_STR_USELANMAN)) {
		login->use_lanman = tds_config_boolean(option, value, login);
	} else if (!strcmp(option, TDS_STR_REALM)) {
		s = tds_dstr_copy(&login->server_realm_name, value);
	} else if (!strcmp(option, TDS_STR_SPN)) {
		s = tds_dstr_copy(&login->server_spn, value);
	} else if (!strcmp(option, TDS_STR_CAFILE)) {
		s = tds_dstr_copy(&login->cafile, value);
	} else if (!strcmp(option, TDS_STR_CRLFILE)) {
		s = tds_dstr_copy(&login->crlfile, value);
	} else if (!strcmp(option, TDS_STR_CHECKSSLHOSTNAME)) {
		login->check_ssl_hostname = tds_config_boolean(option, value, login);
	} else if (!strcmp(option, TDS_STR_DBFILENAME)) {
		s = tds_dstr_copy(&login->db_filename, value);
	} else if (!strcmp(option, TDS_STR_DATABASE)) {
		s = tds_dstr_copy(&login->database, value);
	} else if (!strcmp(option, TDS_STR_READONLY_INTENT)) {
		login->readonly_intent = tds_config_boolean(option, value, login);
		tdsdump_log(TDS_DBG_FUNC, "Setting ReadOnly Intent to '%s'.\n", value);
	} else {
		tdsdump_log(TDS_DBG_INFO1, "UNRECOGNIZED option '%s' ... ignoring.\n", option);
	}

	if (!s)
		login->valid_configuration = 0;
}
Esempio n. 22
0
/**
 * Build a GSSAPI packet to send to server
 * @param tds     A pointer to the TDSSOCKET structure managing a client/server operation.
 * @param packet  GSSAPI packet build from function
 * @return size of packet
 */
TDSAUTHENTICATION * 
tds_gss_get_auth(TDSSOCKET * tds)
{
	/*
	 * TODO
	 * There are some differences between this implementation and MS on
	 * - MS use SPNEGO with 3 mechnisms (MS KRB5, KRB5, NTLMSSP)
	 * - MS seems to use MUTUAL flag
	 * - name type is "Service and Instance (2)" and not "Principal (1)"
	 * check for memory leaks
	 * check for errors in many functions
	 * a bit more verbose
	 * dinamically load library ??
	 */
	gss_buffer_desc send_tok;
	OM_uint32 maj_stat, min_stat;
	/* same as GSS_KRB5_NT_PRINCIPAL_NAME but do not require .so library */
	static gss_OID_desc nt_principal = { 10, (void*) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01" };
	const char *server_name;
	/* Storage for getaddrinfo calls */
	struct addrinfo *addrs = NULL;

	struct tds_gss_auth *auth = (struct tds_gss_auth *) calloc(1, sizeof(struct tds_gss_auth));

	if (!auth || !tds->login)
		return NULL;

	auth->tds_auth.free = tds_gss_free;
	auth->tds_auth.handle_next = tds_gss_handle_next;
	auth->gss_context = GSS_C_NO_CONTEXT;
	auth->last_stat = GSS_S_COMPLETE;

	server_name = tds_dstr_cstr(&tds->login->server_host_name);
	if (strchr(server_name, '.') == NULL) {
		struct addrinfo hints;
		memset(&hints, 0, sizeof(hints));
		hints.ai_family = AF_UNSPEC;
		hints.ai_flags = AI_V4MAPPED|AI_ADDRCONFIG|AI_CANONNAME|AI_FQDN;
		if (!getaddrinfo(server_name, NULL, &hints, &addrs) && addrs->ai_canonname
		    && strchr(addrs->ai_canonname, '.') != NULL)
			server_name = addrs->ai_canonname;
	}

	if (!tds_dstr_isempty(&tds->login->server_spn)) {
		auth->sname = strdup(tds_dstr_cstr(&tds->login->server_spn));
	} else if (tds_dstr_isempty(&tds->login->server_realm_name)) {
		if (asprintf(&auth->sname, "MSSQLSvc/%s:%d", server_name, tds->login->port) < 0)
			auth->sname = NULL;
	} else {
		if (asprintf(&auth->sname, "MSSQLSvc/%s:%d@%s", server_name, tds->login->port,
		             tds_dstr_cstr(&tds->login->server_realm_name)) < 0)
			auth->sname = NULL;
	}
	if (addrs)
		freeaddrinfo(addrs);
	if (auth->sname == NULL) {
		tds_gss_free(tds->conn, (TDSAUTHENTICATION *) auth);
		return NULL;
	}
	tdsdump_log(TDS_DBG_NETWORK, "using kerberos name %s\n", auth->sname);

	/*
	 * Import the name into target_name.  Use send_tok to save
	 * local variable space.
	 */
	send_tok.value = auth->sname;
	send_tok.length = strlen(auth->sname);
	maj_stat = gss_import_name(&min_stat, &send_tok, &nt_principal, &auth->target_name);

	switch (maj_stat) {
	case GSS_S_COMPLETE: 
		tdsdump_log(TDS_DBG_NETWORK, "gss_import_name: GSS_S_COMPLETE: gss_import_name completed successfully.\n");
		if (TDS_FAILED(tds_gss_continue(tds, auth, GSS_C_NO_BUFFER))) {
			tds_gss_free(tds->conn, (TDSAUTHENTICATION *) auth);
			return NULL;
		}
		break;
	case GSS_S_BAD_NAMETYPE: 
		tdsdump_log(TDS_DBG_NETWORK, "gss_import_name: GSS_S_BAD_NAMETYPE: The input_name_type was unrecognized.\n");
		break;
	case GSS_S_BAD_NAME: 
		tdsdump_log(TDS_DBG_NETWORK, "gss_import_name: GSS_S_BAD_NAME: The input_name parameter could not be interpreted as a name of the specified type.\n");
		break;
	case GSS_S_BAD_MECH:
		tdsdump_log(TDS_DBG_NETWORK, "gss_import_name: GSS_S_BAD_MECH: The input name-type was GSS_C_NT_EXPORT_NAME, but the mechanism contained within the input-name is not supported.\n");
		break;
	default:
		tdsdump_log(TDS_DBG_NETWORK, "gss_import_name: unexpected error %d.\n", maj_stat);
		break;
	}

	if (GSS_ERROR(maj_stat)) {
		tds_gss_free(tds->conn, (TDSAUTHENTICATION *) auth);
		return NULL;
	}

	return (TDSAUTHENTICATION *) auth;
}
Esempio n. 23
0
static TDSRET
tds5_negotiate_handle_next(TDSSOCKET * tds, TDSAUTHENTICATION * tds_auth, size_t len)
{
	TDS5NEGOTIATE *auth = (TDS5NEGOTIATE *) tds_auth;
	TDSPARAMINFO *info;
	void *rsa, *nonce = NULL;
	size_t rsa_len, nonce_len = 0;
	void *em;
	size_t em_size;
	TDSRET rc = TDS_FAIL;

	/* send next data for authentication */

	if (!tds->login)
		goto error;

	/* we only support RSA authentication, we should have send 2/3 parameters:
	 * 1- integer.. unknown actually 1 TODO
	 * 2- binary, rsa public key in PEM format
	 * 3- binary, nonce (optional)
	 */

	/* message not supported */
	if (auth->msg_type != 0x1e)
		goto error;

	info = tds->param_info;
	if (!info || info->num_cols < 2)
		goto error;

	if (info->columns[1]->column_type != SYBLONGBINARY)
		goto error;
	if (info->num_cols >= 3 && info->columns[2]->column_type != SYBLONGBINARY)
		goto error;
	rsa = ((TDSBLOB*) info->columns[1]->column_data)->textvalue;
	rsa_len = info->columns[1]->column_size;
	if (info->num_cols >= 3) {
		nonce = ((TDSBLOB*) info->columns[2]->column_data)->textvalue;
		nonce_len = info->columns[2]->column_size;
	}

	em = tds5_rsa_encrypt(rsa, rsa_len, nonce, nonce_len, tds_dstr_cstr(&tds->login->password), &em_size);
	if (!em)
		goto error;

	tds->out_flag = TDS_NORMAL;

	/* password */
	tds5_send_msg(tds, 0x1f);
	tds_put_n(tds, "\xec\x0e\x00\x01\x00\x00\x00\x00\x00\x00\x00\xe1\xff\xff\xff\x7f\x00", 0x11);
	tds_put_byte(tds, TDS5_PARAMS_TOKEN);
	tds_put_int(tds, em_size);
	tds_put_n(tds, em, em_size);

	/* remote password */
	tds5_send_msg(tds, 0x20);
	tds_put_n(tds, "\xec\x17\x00\x02\x00\x00\x00\x00\x00\x00\x00\x27\xff\x00\x00\x00\x00\x00\x00\x00\xe1\xff\xff\xff\x7f\x00", 0x1a);
	tds_put_byte(tds, TDS5_PARAMS_TOKEN);
	tds_put_byte(tds, 0);
	tds_put_int(tds, em_size);
	tds_put_n(tds, em, em_size);

	free(em);

	rc = tds_flush_packet(tds);

error:
	tds5_negotiate_free(tds->conn, tds_auth);
	tds->conn->authentication = NULL;

	return rc;
}
Esempio n. 24
0
/*
 * pool_user_login
 * Reads clients login packet and forges a login acknowledgement sequence 
 */
static bool
pool_user_login(TDS_POOL * pool, TDS_POOL_USER * puser)
{
	TDSSOCKET *tds;
	TDSLOGIN *login;

	tds = puser->sock.tds;
	while (tds->in_len <= tds->in_pos)
		if (tds_read_packet(tds) < 0)
			return false;

	tdsdump_log(TDS_DBG_NETWORK, "got packet type %d\n", tds->in_flag);
	if (tds->in_flag == TDS71_PRELOGIN) {
		if (!tds->conn->tds_version)
			tds->conn->tds_version = 0x701;
		tds->out_flag = TDS_REPLY;
		// TODO proper one !!
		// TODO detect TDS version here ??
		tds_put_n(tds,  "\x00\x00\x1a\x00\x06" /* version */
				"\x01\x00\x20\x00\x01" /* encryption */
				"\x02\x00\x21\x00\x01" /* instance ?? */
				"\x03\x00\x22\x00\x00" /* process id ?? */
				"\x04\x00\x22\x00\x01" /* MARS */
				"\xff"
				"\x0a\x00\x06\x40\x00\x00"
				"\x02"
				"\x01"
				""
				"\x00", 0x23);
		tds_flush_packet(tds);

		/* read another packet */
		tds->in_pos = tds->in_len;
		while (tds->in_len <= tds->in_pos)
			if (tds_read_packet(tds) < 0)
				return false;
	}

	puser->login = login = tds_alloc_login(1);
	if (tds->in_flag == TDS_LOGIN) {
		if (!tds->conn->tds_version)
			tds->conn->tds_version = 0x500;
		tds_read_login(tds, login);
	} else if (tds->in_flag == TDS7_LOGIN) {
		if (!tds->conn->tds_version)
			tds->conn->tds_version = 0x700;
		if (!tds7_read_login(tds, login))
			return false;
	} else {
		return false;
	}

	/* check we support version required */
	// TODO function to check it
	if (!IS_TDS71_PLUS(login))
		return false;

	tds->in_len = tds->in_pos = 0;

	dump_login(login);
	if (strcmp(tds_dstr_cstr(&login->user_name), pool->user) != 0
	    || strcmp(tds_dstr_cstr(&login->password), pool->password) != 0)
		/* TODO send nack before exiting */
		return false;

	return true;
}
Esempio n. 25
0
static void
tds_config_login(TDSLOGIN * connection, TDSLOGIN * login)
{
	if (!tds_dstr_isempty(&login->server_name)) {
		if (1 || tds_dstr_isempty(&connection->server_name)) 
			tds_dstr_dup(&connection->server_name, &login->server_name);
	}
	if (login->tds_version)
		connection->tds_version = login->tds_version;
	if (!tds_dstr_isempty(&login->language)) {
		tds_dstr_dup(&connection->language, &login->language);
	}
	if (!tds_dstr_isempty(&login->server_charset)) {
		tds_dstr_dup(&connection->server_charset, &login->server_charset);
	}
	if (!tds_dstr_isempty(&login->client_charset)) {
		tds_dstr_dup(&connection->client_charset, &login->client_charset);
		tdsdump_log(TDS_DBG_INFO1, "tds_config_login: %s is %s.\n", "client_charset",
			    tds_dstr_cstr(&connection->client_charset));
	}
	if (!tds_dstr_isempty(&login->database)) {
		tds_dstr_dup(&connection->database, &login->database);
		tdsdump_log(TDS_DBG_INFO1, "tds_config_login: %s is %s.\n", "database_name",
			    tds_dstr_cstr(&connection->database));
	}
	if (!tds_dstr_isempty(&login->client_host_name)) {
		tds_dstr_dup(&connection->client_host_name, &login->client_host_name);
	}
	if (!tds_dstr_isempty(&login->app_name)) {
		tds_dstr_dup(&connection->app_name, &login->app_name);
	}
	if (!tds_dstr_isempty(&login->user_name)) {
		tds_dstr_dup(&connection->user_name, &login->user_name);
	}
	if (!tds_dstr_isempty(&login->password)) {
		/* for security reason clear memory */
		tds_dstr_zero(&connection->password);
		tds_dstr_dup(&connection->password, &login->password);
	}
	if (!tds_dstr_isempty(&login->library)) {
		tds_dstr_dup(&connection->library, &login->library);
	}
	if (login->encryption_level) {
		connection->encryption_level = login->encryption_level;
	}
	if (login->suppress_language) {
		connection->suppress_language = 1;
	}
	if (login->bulk_copy) {
		connection->bulk_copy = 1;
	}
	if (login->block_size) {
		connection->block_size = login->block_size;
	}
	if (login->port)
		connection->port = login->port;
	if (login->connect_timeout)
		connection->connect_timeout = login->connect_timeout;

	if (login->query_timeout)
		connection->query_timeout = login->query_timeout;

	/* copy other info not present in configuration file */
	connection->capabilities = login->capabilities;
}
Esempio n. 26
0
bool
pool_user_send_login_ack(TDS_POOL * pool, TDS_POOL_USER * puser)
{
	char msg[256];
	char block[32];
	TDSSOCKET *tds = puser->sock.tds, *mtds = puser->assigned_member->sock.tds;
	TDSLOGIN *login = puser->login;
	const char *database;
	const char *server = mtds->conn->server ? mtds->conn->server : "JDBC";
	bool dbname_mismatch, odbc_mismatch;

	pool->user_logins++;

	/* copy a bit of information, resize socket with block */
	tds->conn->tds_version = mtds->conn->tds_version;
	tds->conn->product_version = mtds->conn->product_version;
	memcpy(tds->conn->collation, mtds->conn->collation, sizeof(tds->conn->collation));
	tds->conn->tds71rev1 = mtds->conn->tds71rev1;
	free(tds->conn->product_name);
	tds->conn->product_name = strdup(mtds->conn->product_name);
	tds_realloc_socket(tds, mtds->conn->env.block_size);
	tds->conn->env.block_size = mtds->conn->env.block_size;
	tds->conn->client_spid = mtds->conn->spid;

	/* if database is different use USE statement */
	database = pool->database;
	dbname_mismatch = !tds_dstr_isempty(&login->database)
			  && strcasecmp(tds_dstr_cstr(&login->database), database) != 0;
	odbc_mismatch = (login->option_flag2 & TDS_ODBC_ON) == 0;
	if (dbname_mismatch || odbc_mismatch) {
		char *str;
		int len = 128 + tds_quote_id(mtds, NULL, tds_dstr_cstr(&login->database),-1);
		TDSRET ret;

		if ((str = (char *) malloc(len)) == NULL)
			return false;

		str[0] = 0;
		/* swicth to dblib options */
		if (odbc_mismatch)
			strcat(str, "SET ANSI_DEFAULTS OFF\nSET CONCAT_NULL_YIELDS_NULL OFF\n");
		if (dbname_mismatch) {
			strcat(str, "USE ");
			tds_quote_id(mtds, strchr(str, 0), tds_dstr_cstr(&login->database), -1);
		}
		ret = tds_submit_query(mtds, str);
		free(str);
		if (TDS_FAILED(ret) || TDS_FAILED(tds_process_simple_query(mtds)))
			return false;
		if (dbname_mismatch)
			database = tds_dstr_cstr(&login->database);
		else
			database = mtds->conn->env.database;
	}

	// 7.0
	// env database
	// database change message (with server name correct)
	// env language
	// language change message
	// env 0x3 charset ("iso_1")
	// env 0x5 lcid ("1033")
	// env 0x6 ("196609" ?? 0x30001)
	// loginack
	// env 0x4 packet size
	// done
	//
	// 7.1/7.2/7.3
	// env database
	// database change message (with server name correct)
	// env 0x7 collation
	// env language
	// language change message
	// loginack
	// env 0x4 packet size
	// done
	tds->out_flag = TDS_REPLY;
	tds_env_change(tds, TDS_ENV_DATABASE, "master", database);
	sprintf(msg, "Changed database context to '%s'.", database);
	tds_send_msg(tds, 5701, 2, 0, msg, server, NULL, 1);
	if (!login->suppress_language) {
		tds_env_change(tds, TDS_ENV_LANG, NULL, "us_english");
		tds_send_msg(tds, 5703, 1, 0, "Changed language setting to 'us_english'.", server, NULL, 1);
	}

	if (IS_TDS71_PLUS(tds->conn)) {
		tds_put_byte(tds, TDS_ENVCHANGE_TOKEN);
		tds_put_smallint(tds, 8);
		tds_put_byte(tds, TDS_ENV_SQLCOLLATION);
		tds_put_byte(tds, 5);
		tds_put_n(tds, tds->conn->collation, 5);
		tds_put_byte(tds, 0);
	}

	tds_send_login_ack(tds, mtds->conn->product_name);
	sprintf(block, "%d", tds->conn->env.block_size);
	tds_env_change(tds, TDS_ENV_PACKSIZE, block, block);
	/* tds_send_capabilities_token(tds); */
	tds_send_done_token(tds, 0, 0);

	/* send it! */
	tds_flush_packet(tds);

	tds_free_login(login);
	puser->login = NULL;
	return true;
}
Esempio n. 27
0
int
main(int argc, char **argv)
{
	TDSLOGIN *login;
	TDSSOCKET *tds;
	int verbose = 0;
	int num_cols = 2;
	TDS_INT result_type;
	int rc;
	int i, done_flags;

	fprintf(stdout, "%s: Test basic submit query, results\n", __FILE__);
	rc = try_tds_login(&login, &tds, __FILE__, verbose);
	if (rc != TDS_SUCCESS) {
		fprintf(stderr, "try_tds_login() failed\n");
		return 1;
	}

	rc = tds_submit_query(tds, "select db_name() dbname, user_name() username");
	if (rc != TDS_SUCCESS) {
		fprintf(stderr, "tds_submit_query() failed\n");
		return 1;
	}

	while ((rc = tds_process_tokens(tds, &result_type, &done_flags, TDS_TOKEN_RESULTS)) == TDS_SUCCESS) {
		switch (result_type) {
		case TDS_ROWFMT_RESULT:
			if (tds->res_info->num_cols != num_cols) {
				fprintf(stderr, "Error:  num_cols != %d in %s\n", num_cols, __FILE__);
				return 1;
			}
			if (tds->res_info->columns[0]->column_type != SYBVARCHAR
			    || tds->res_info->columns[1]->column_type != SYBVARCHAR) {
				fprintf(stderr, "Wrong column_type in %s\n", __FILE__);
				return 1;
			}
			if (strcmp(tds_dstr_cstr(&tds->res_info->columns[0]->column_name), "dbname")
			    || strcmp(tds_dstr_cstr(&tds->res_info->columns[1]->column_name), "username")) {
				fprintf(stderr, "Wrong column_name in %s\n", __FILE__);
				return 1;
			}
			break;

		case TDS_ROW_RESULT:

			while ((rc = tds_process_tokens(tds, &result_type, NULL, TDS_STOPAT_ROWFMT|TDS_RETURN_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE)) == TDS_SUCCESS) {
				if (result_type != TDS_ROW_RESULT || result_type != TDS_COMPUTE_RESULT)
					break;
				if (verbose) {
					for (i = 0; i < num_cols; i++) {
						printf("col %i is %s\n", i, value_as_string(tds, i));
					}
				}
			}
			if (rc != TDS_SUCCESS) {
				fprintf(stderr, "tds_process_tokens() unexpected return\n");
			}
			break;

		case TDS_DONE_RESULT:
		case TDS_DONEPROC_RESULT:
		case TDS_DONEINPROC_RESULT:
			if (!(done_flags & TDS_DONE_ERROR))
				break;

		default:
			fprintf(stderr, "tds_process_tokens() unexpected result_type\n");
			break;
		}
	}
	if (rc != TDS_NO_MORE_RESULTS) {
		fprintf(stderr, "tds_process_tokens() unexpected return\n");
	}

	try_tds_logout(login, tds, verbose);
	return 0;
}
Esempio n. 28
0
/**
 * Build a SSPI packet to send to server
 * @param tds     A pointer to the TDSSOCKET structure managing a client/server operation.
 */
TDSAUTHENTICATION *
tds_sspi_get_auth(TDSSOCKET * tds)
{
	SecBuffer buf;
	SecBufferDesc desc;
	SECURITY_STATUS status;
	ULONG attrs;
	TimeStamp ts;
	SEC_WINNT_AUTH_IDENTITY identity;
	const char *p, *user_name, *server_name;

	TDSSSPIAUTH *auth;
	TDSCONNECTION *connection = tds->connection;

	/* check connection */
	if (!connection)
		return NULL;

	if (!tds_init_secdll())
		return NULL;

	/* parse username/password informations */
	memset(&identity, 0, sizeof(identity));
	user_name = tds_dstr_cstr(&connection->user_name);
	if ((p = strchr(user_name, '\\')) != NULL) {
		identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
		identity.Password = (void *) tds_dstr_cstr(&connection->password);
		identity.PasswordLength = tds_dstr_len(&connection->password);
		identity.Domain = (void *) user_name;
		identity.DomainLength = p - user_name;
		user_name = p + 1;
		identity.User = (void *) user_name;
		identity.UserLength = strlen(user_name);
	}

	auth = (TDSSSPIAUTH *) calloc(1, sizeof(TDSSSPIAUTH));
	if (!auth || !tds->connection)
		return NULL;

	auth->tds_auth.free = tds_sspi_free;
	auth->tds_auth.handle_next = tds_sspi_handle_next;

	/* using Negotiate system will use proper protocol (either NTLM or Kerberos) */
	if (sec_fn->AcquireCredentialsHandleA(NULL, (char *)"Negotiate", SECPKG_CRED_OUTBOUND,
		NULL, identity.Domain ? &identity : NULL,
		NULL, NULL, &auth->cred, &ts) != SEC_E_OK) {
		free(auth);
		return NULL;
	}

	/* allocate buffer */
	auth->tds_auth.packet = (TDS_UCHAR *) malloc(NTLMBUF_LEN);
	if (!auth->tds_auth.packet) {
		sec_fn->FreeCredentialsHandle(&auth->cred);
		free(auth);
		return NULL;
	}
	desc.ulVersion = SECBUFFER_VERSION;
	desc.cBuffers  = 1;
	desc.pBuffers  = &buf;

	buf.cbBuffer   = NTLMBUF_LEN;
	buf.BufferType = SECBUFFER_TOKEN;
	buf.pvBuffer   = auth->tds_auth.packet;

	/* build SPN */
	server_name = tds_dstr_cstr(&connection->server_host_name);
	if (strchr(server_name, '.') == NULL) {
		struct hostent *host = gethostbyname(server_name);
		if (host && strchr(host->h_name, '.') != NULL)
			server_name = host->h_name;
	}
	if (strchr(server_name, '.') != NULL) {
		if (asprintf(&auth->sname, "MSSQLSvc/%s:%d", server_name, connection->port) < 0) {
			free(auth->tds_auth.packet);
			sec_fn->FreeCredentialsHandle(&auth->cred);
			free(auth);
			return NULL;
		}
		tdsdump_log(TDS_DBG_NETWORK, "kerberos name %s\n", auth->sname);
	}

	status = sec_fn->InitializeSecurityContextA(&auth->cred, NULL, auth->sname,
		ISC_REQ_CONFIDENTIALITY | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONNECTION,
		0, SECURITY_NETWORK_DREP,
		NULL, 0,
		&auth->cred_ctx, &desc,
		&attrs, &ts);

	if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
		sec_fn->CompleteAuthToken(&auth->cred_ctx, &desc);
	} else if(status != SEC_E_OK) {
		free(auth->sname);
		free(auth->tds_auth.packet);
		sec_fn->FreeCredentialsHandle(&auth->cred);
		free(auth);
		return NULL;
	}

	auth->tds_auth.packet_len = buf.cbBuffer;
	return &auth->tds_auth;
}
Esempio n. 29
0
TDSRET
tds_ssl_init(TDSSOCKET *tds)
{
	gnutls_session_t session;
	gnutls_certificate_credentials_t xcred;
	int ret;
	const char *tls_msg;

	xcred = NULL;
	session = NULL;	
	tls_msg = "initializing tls";

	if (!tls_initialized) {
		ret = 0;
		tds_mutex_lock(&tls_mutex);
		if (!tls_initialized) {
			tds_gcry_init();
			ret = gnutls_global_init();
			if (ret == 0)
				tls_initialized = 1;
		}
		tds_mutex_unlock(&tls_mutex);
		if (ret != 0)
			goto cleanup;
	}

	if (tds_write_dump && tls_initialized < 2) {
		gnutls_global_set_log_level(11);
		gnutls_global_set_log_function(tds_tls_log);
		tls_initialized = 2;
	}

	tls_msg = "allocating credentials";
	ret = gnutls_certificate_allocate_credentials(&xcred);
	if (ret != 0)
		goto cleanup;

	if (!tds_dstr_isempty(&tds->login->cafile)) {
		tls_msg = "loading CA file";
		if (strcasecmp(tds_dstr_cstr(&tds->login->cafile), "system") == 0)
			ret = gnutls_certificate_set_x509_system_trust(xcred);
		else
			ret = gnutls_certificate_set_x509_trust_file(xcred, tds_dstr_cstr(&tds->login->cafile), GNUTLS_X509_FMT_PEM);
		if (ret <= 0)
			goto cleanup;
		if (!tds_dstr_isempty(&tds->login->crlfile)) {
			tls_msg = "loading CRL file";
			ret = gnutls_certificate_set_x509_crl_file(xcred, tds_dstr_cstr(&tds->login->crlfile), GNUTLS_X509_FMT_PEM);
			if (ret <= 0)
				goto cleanup;
		}
#ifdef HAVE_GNUTLS_CERTIFICATE_SET_VERIFY_FUNCTION
		gnutls_certificate_set_verify_function(xcred, tds_verify_certificate);
#endif
	}

	/* Initialize TLS session */
	tls_msg = "initializing session";
	ret = gnutls_init(&session, GNUTLS_CLIENT);
	if (ret != 0)
		goto cleanup;

	gnutls_transport_set_ptr(session, tds);
	gnutls_transport_set_pull_function(session, tds_pull_func_login);
	gnutls_transport_set_push_function(session, tds_push_func_login);

	/* NOTE: there functions return int however they cannot fail */

	/* use default priorities... */
	gnutls_set_default_priority(session);

	/* ... but overwrite some */
	ret = gnutls_priority_set_direct (session, "NORMAL:%COMPAT:-VERS-SSL3.0", NULL);
	if (ret != 0)
		goto cleanup;

	/* mssql does not like padding too much */
#ifdef HAVE_GNUTLS_RECORD_DISABLE_PADDING
	gnutls_record_disable_padding(session);
#endif

	/* put the anonymous credentials to the current session */
	tls_msg = "setting credential";
	ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred);
	if (ret != 0)
		goto cleanup;

	/* Perform the TLS handshake */
	tls_msg = "handshake";
	ret = gnutls_handshake (session);
	if (ret != 0)
		goto cleanup;

#ifndef HAVE_GNUTLS_CERTIFICATE_SET_VERIFY_FUNCTION
	ret = tds_verify_certificate(session);
	if (ret != 0)
		goto cleanup;
#endif

	tdsdump_log(TDS_DBG_INFO1, "handshake succeeded!!\n");

	gnutls_transport_set_ptr(session, tds->conn);
	gnutls_transport_set_pull_function(session, tds_pull_func);
	gnutls_transport_set_push_function(session, tds_push_func);

	tds->conn->tls_session = session;
	tds->conn->tls_credentials = xcred;

	return TDS_SUCCESS;

cleanup:
	if (session)
		gnutls_deinit(session);
	if (xcred)
		gnutls_certificate_free_credentials(xcred);
	tdsdump_log(TDS_DBG_ERROR, "%s failed: %s\n", tls_msg, gnutls_strerror (ret));
	return TDS_FAIL;
}
Esempio n. 30
0
int
tds_ssl_init(TDSSOCKET *tds)
{
#define OPENSSL_CIPHERS \
	"DHE-RSA-AES256-SHA DHE-DSS-AES256-SHA " \
	"AES256-SHA EDH-RSA-DES-CBC3-SHA " \
	"EDH-DSS-DES-CBC3-SHA DES-CBC3-SHA " \
	"DES-CBC3-MD5 DHE-RSA-AES128-SHA " \
	"DHE-DSS-AES128-SHA AES128-SHA RC2-CBC-MD5 RC4-SHA RC4-MD5"

	SSL *con;
	SSL_CTX *ctx;
	BIO *b, *b2;

	int ret;
	const char *tls_msg;

	con = NULL;
	b = NULL;
	b2 = NULL;
	ret = 1;

	tds_check_wildcard_test();

	tds_ssl_deinit(tds->conn);

	tls_msg = "initializing tls";
	ctx = tds_init_openssl();
	if (!ctx)
		goto cleanup;

	if (!tds_dstr_isempty(&tds->login->cafile)) {
		tls_msg = "loading CA file";
		if (strcasecmp(tds_dstr_cstr(&tds->login->cafile), "system") == 0)
			ret = SSL_CTX_set_default_verify_paths(ctx);
		else
			ret = SSL_CTX_load_verify_locations(ctx, tds_dstr_cstr(&tds->login->cafile), NULL);
		if (ret != 1)
			goto cleanup;
		if (!tds_dstr_isempty(&tds->login->crlfile)) {
			X509_STORE *store = SSL_CTX_get_cert_store(ctx);
			X509_LOOKUP *lookup;

			tls_msg = "loading CRL file";
			if (!(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()))
			    || (!X509_load_crl_file(lookup, tds_dstr_cstr(&tds->login->crlfile), X509_FILETYPE_PEM)))
				goto cleanup;

			X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
		}
		SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
	}

	/* Initialize TLS session */
	tls_msg = "initializing session";
	con = SSL_new(ctx);
	if (!con)
		goto cleanup;

	tls_msg = "creating bio";
	b = BIO_new(&tds_method_login);
	if (!b)
		goto cleanup;

	b2 = BIO_new(&tds_method);
	if (!b2)
		goto cleanup;

	b->shutdown=1;
	b->init=1;
	b->num= -1;
	b->ptr = tds;
	BIO_set_conn_hostname(b, tds_dstr_cstr(&tds->login->server_host_name));
	SSL_set_bio(con, b, b);
	b = NULL;

	/* use priorities... */
	SSL_set_cipher_list(con, OPENSSL_CIPHERS);

#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
	/* this disable a security improvement but allow connection... */
	SSL_set_options(con, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
#endif

	/* Perform the TLS handshake */
	tls_msg = "handshake";
	SSL_set_connect_state(con);
	ret = SSL_connect(con) != 1 || con->state != SSL_ST_OK;
	if (ret != 0)
		goto cleanup;

	/* check certificate hostname */
	if (!tds_dstr_isempty(&tds->login->cafile) && tds->login->check_ssl_hostname) {
		X509 *cert;

		cert =  SSL_get_peer_certificate(con);
		tls_msg = "checking hostname";
		if (!cert || !check_hostname(cert, tds_dstr_cstr(&tds->login->server_host_name)))
			goto cleanup;
	}

	tdsdump_log(TDS_DBG_INFO1, "handshake succeeded!!\n");

	b2->shutdown = 1;
	b2->init = 1;
	b2->num = -1;
	b2->ptr = tds->conn;
	SSL_set_bio(con, b2, b2);

	tds->conn->tls_session = con;
	tds->conn->tls_ctx = ctx;

	return TDS_SUCCESS;

cleanup:
	if (b2)
		BIO_free(b2);
	if (b)
		BIO_free(b);
	if (con) {
		SSL_shutdown(con);
		SSL_free(con);
	}
	SSL_CTX_free(ctx);
	tdsdump_log(TDS_DBG_ERROR, "%s failed\n", tls_msg);
	return TDS_FAIL;
}