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; }
/** * 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; }
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; }
/** * 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; }
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; }
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; }
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; }
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; }
/** * 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; }
static void tds_config_login(TDSCONNECTINFO * connect_info, TDSLOGIN * login) { if (!tds_dstr_isempty(&login->server_name)) { tds_dstr_copy(&connect_info->server_name, tds_dstr_cstr(&login->server_name)); } if (login->major_version || login->minor_version) { connect_info->major_version = login->major_version; connect_info->minor_version = login->minor_version; } if (!tds_dstr_isempty(&login->language)) { tds_dstr_copy(&connect_info->language, tds_dstr_cstr(&login->language)); } if (!tds_dstr_isempty(&login->server_charset)) { tds_dstr_copy(&connect_info->server_charset, tds_dstr_cstr(&login->server_charset)); } if (!tds_dstr_isempty(&login->client_charset)) { tds_dstr_copy(&connect_info->client_charset, tds_dstr_cstr(&login->client_charset)); tdsdump_log(TDS_DBG_INFO1, "%L tds_config_login:%d: %s is %s.\n", __LINE__, "client_charset", connect_info->client_charset); } if (!tds_dstr_isempty(&login->host_name)) { tds_dstr_copy(&connect_info->host_name, tds_dstr_cstr(&login->host_name)); /* DBSETLHOST and it's equivilants are commentary fields * ** they don't affect connect_info->ip_addr (the server) but they show * ** up in an sp_who as the *clients* hostname. (bsb, 11/10) */ /* should work with IP (mlilback, 11/7/01) */ /* * if (connect_info->ip_addr) free(connect_info->ip_addr); * connect_info->ip_addr = calloc(sizeof(char),18); * tds_lookup_host(connect_info->host_name, NULL, connect_info->ip_addr, NULL); */ } if (!tds_dstr_isempty(&login->app_name)) { tds_dstr_copy(&connect_info->app_name, tds_dstr_cstr(&login->app_name)); } if (!tds_dstr_isempty(&login->user_name)) { tds_dstr_copy(&connect_info->user_name, tds_dstr_cstr(&login->user_name)); } if (!tds_dstr_isempty(&login->password)) { /* for security reason clear memory */ tds_dstr_zero(&connect_info->password); tds_dstr_copy(&connect_info->password, tds_dstr_cstr(&login->password)); } if (!tds_dstr_isempty(&login->library)) { tds_dstr_copy(&connect_info->library, tds_dstr_cstr(&login->library)); } if (login->encrypted) { connect_info->encrypted = 1; } if (login->suppress_language) { connect_info->suppress_language = 1; } if (login->bulk_copy) { connect_info->bulk_copy = 1; } if (login->block_size) { connect_info->block_size = login->block_size; } if (login->port) { connect_info->port = login->port; } if (login->connect_timeout) connect_info->connect_timeout = login->connect_timeout; /* copy other info not present in configuration file */ connect_info->query_timeout = login->query_timeout; connect_info->longquery_timeout = login->longquery_timeout; connect_info->longquery_func = login->longquery_func; connect_info->longquery_param = login->longquery_param; memcpy(connect_info->capabilities, login->capabilities, TDS_MAX_CAPABILITY); }
/** * Callback function for the DSN Configuration dialog * \param hDlg identifies the dialog * \param message what happened to the dialog * \param wParam varies with message * \param lParam pointer to TDSLOGIN struct */ static BOOL CALLBACK LoginDlgProc(HWND hDlg, UINT message, WPARAM wParam, /* */ LPARAM lParam) { TDSLOGIN *login; char tmp[100]; switch (message) { case WM_INITDIALOG: /* lParam points to the TDSLOGIN */ login = (TDSLOGIN *) lParam; SetWindowUserData(hDlg, lParam); /* copy info from TDSLOGIN to the dialog */ SendDlgItemMessage(hDlg, IDC_LOGINSERVER, WM_SETTEXT, 0, (LPARAM) tds_dstr_cstr(&login->server_name)); SendDlgItemMessage(hDlg, IDC_LOGINUID, WM_SETTEXT, 0, (LPARAM) tds_dstr_cstr(&login->user_name)); SendDlgItemMessage(hDlg, IDC_LOGINUID, EM_LIMITTEXT, sizeof(tmp) - 1, 0); SendDlgItemMessage(hDlg, IDC_LOGINPWD, WM_SETTEXT, 0, (LPARAM) tds_dstr_cstr(&login->password)); SendDlgItemMessage(hDlg, IDC_LOGINPWD, EM_LIMITTEXT, sizeof(tmp) - 1, 0); SendDlgItemMessage(hDlg, IDC_LOGINDUMP, BM_SETCHECK, !tds_dstr_isempty(&login->dump_file), 0L); /* adjust label of logging checkbox */ SendDlgItemMessage(hDlg, IDC_LOGINDUMP, WM_SETTEXT, 0, (LPARAM) "\"FreeTDS.log\" on desktop"); return TRUE; case WM_COMMAND: /* Dialog's user data points to TDSLOGIN */ login = (TDSLOGIN *) GetWindowUserData(hDlg); /* The wParam indicates which button was pressed */ if (LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, FALSE); return TRUE; } else if (LOWORD(wParam) != IDOK) { /* Anything but IDCANCEL or IDOK is handled elsewhere */ break; } /* If we get here, then the user hit the [OK] button */ /* get values from dialog */ SendDlgItemMessage(hDlg, IDC_LOGINUID, WM_GETTEXT, sizeof tmp, (LPARAM) tmp); tds_dstr_copy(&login->user_name, tmp); SendDlgItemMessage(hDlg, IDC_LOGINPWD, WM_GETTEXT, sizeof tmp, (LPARAM) tmp); tds_dstr_copy(&login->password, tmp); if (SendDlgItemMessage(hDlg, IDC_LOGINDUMP, BM_GETCHECK, 0, 0)) { char * filename = get_desktop_file("FreeTDS.log"); if (filename) { tds_dstr_copy(&login->dump_file, filename); free(filename); } } else { tds_dstr_copy(&login->dump_file, ""); } /* And we're done */ EndDialog(hDlg, TRUE); return TRUE; } return FALSE; }
/** * Read connection information from given DSN * @param DSN DSN name * @param login where to store connection info * @return 1 if success 0 otherwhise */ int odbc_get_dsn_info(TDS_ERRS *errs, const char *DSN, TDSLOGIN * login) { char tmp[FILENAME_MAX]; int freetds_conf_less = 1; /* use old servername */ if (myGetPrivateProfileString(DSN, odbc_param_Servername, tmp) > 0) { freetds_conf_less = 0; if (!tds_dstr_copy(&login->server_name, tmp)) { odbc_errs_add(errs, "HY001", NULL); return 0; } tds_read_conf_file(login, tmp); if (myGetPrivateProfileString(DSN, odbc_param_Server, tmp) > 0) { odbc_errs_add(errs, "HY000", "You cannot specify both SERVERNAME and SERVER"); return 0; } if (myGetPrivateProfileString(DSN, odbc_param_Address, tmp) > 0) { odbc_errs_add(errs, "HY000", "You cannot specify both SERVERNAME and ADDRESS"); return 0; } } /* search for server (compatible with ms one) */ if (freetds_conf_less) { int address_specified = 0; if (myGetPrivateProfileString(DSN, odbc_param_Address, tmp) > 0) { address_specified = 1; /* TODO parse like MS */ if (TDS_FAILED(tds_lookup_host_set(tmp, &login->ip_addrs))) { odbc_errs_add(errs, "HY000", "Error parsing ADDRESS attribute"); return 0; } } if (myGetPrivateProfileString(DSN, odbc_param_Server, tmp) > 0) { if (!tds_dstr_copy(&login->server_name, tmp)) { odbc_errs_add(errs, "HY001", NULL); return 0; } if (!address_specified) { if (!parse_server(errs, tmp, login)) return 0; } } } if (myGetPrivateProfileString(DSN, odbc_param_Port, tmp) > 0) tds_parse_conf_section(TDS_STR_PORT, tmp, login); if (myGetPrivateProfileString(DSN, odbc_param_TDS_Version, tmp) > 0) tds_parse_conf_section(TDS_STR_VERSION, tmp, login); if (myGetPrivateProfileString(DSN, odbc_param_Language, tmp) > 0) tds_parse_conf_section(TDS_STR_LANGUAGE, tmp, login); if (tds_dstr_isempty(&login->database) && myGetPrivateProfileString(DSN, odbc_param_Database, tmp) > 0) if (!tds_dstr_copy(&login->database, tmp)) { odbc_errs_add(errs, "HY001", NULL); return 0; } if (myGetPrivateProfileString(DSN, odbc_param_TextSize, tmp) > 0) tds_parse_conf_section(TDS_STR_TEXTSZ, tmp, login); if (myGetPrivateProfileString(DSN, odbc_param_PacketSize, tmp) > 0) tds_parse_conf_section(TDS_STR_BLKSZ, tmp, login); if (myGetPrivateProfileString(DSN, odbc_param_ClientCharset, tmp) > 0) tds_parse_conf_section(TDS_STR_CLCHARSET, tmp, login); if (myGetPrivateProfileString(DSN, odbc_param_DumpFile, tmp) > 0) tds_parse_conf_section(TDS_STR_DUMPFILE, tmp, login); if (myGetPrivateProfileString(DSN, odbc_param_DumpFileAppend, tmp) > 0) tds_parse_conf_section(TDS_STR_APPENDMODE, tmp, login); if (myGetPrivateProfileString(DSN, odbc_param_DebugFlags, tmp) > 0) tds_parse_conf_section(TDS_STR_DEBUGFLAGS, tmp, login); if (myGetPrivateProfileString(DSN, odbc_param_Encryption, tmp) > 0) tds_parse_conf_section(TDS_STR_ENCRYPTION, tmp, login); if (myGetPrivateProfileString(DSN, odbc_param_UseNTLMv2, tmp) > 0) tds_parse_conf_section(TDS_STR_USENTLMV2, tmp, login); if (myGetPrivateProfileString(DSN, odbc_param_REALM, tmp) > 0) tds_parse_conf_section(TDS_STR_REALM, tmp, login); if (myGetPrivateProfileString(DSN, odbc_param_ServerSPN, tmp) > 0) tds_parse_conf_section(TDS_STR_SPN, tmp, login); if (myGetPrivateProfileString(DSN, odbc_param_Trusted_Connection, tmp) > 0 && tds_config_boolean(odbc_param_Trusted_Connection, tmp, login)) { tds_dstr_empty(&login->user_name); tds_dstr_empty(&login->password); } if (myGetPrivateProfileString(DSN, odbc_param_MARS_Connection, tmp) > 0 && tds_config_boolean(odbc_param_MARS_Connection, tmp, login)) { login->mars = 1; } if (myGetPrivateProfileString(DSN, odbc_param_AttachDbFilename, tmp) > 0) tds_parse_conf_section(TDS_STR_DBFILENAME, tmp, login); return 1; }