/** * 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 */ }
/** * 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; }
/** * Parse connection string and fill connect_info according * @param connect_string connect string * @param connect_string_end connect string end (pointer to char past last) * @param connect_info where to store connection info * @return 1 if success 0 otherwhise */ int odbc_parse_connect_string(const char *connect_string, const char *connect_string_end, TDSCONNECTINFO * connect_info) { const char *p, *end; DSTR *dest_s, value; int reparse = 0; /* flag for indicate second parse of string */ char option[16]; char tmp[256]; tds_dstr_init(&value); for (p = connect_string; p && *p;) { dest_s = NULL; /* parse option */ end = (const char *) memchr(p, '=', connect_string_end - p); if (!end) break; /* account for spaces between ;'s. */ while (p < end && *p == ' ') ++p; if ((end - p) >= (int) sizeof(option)) option[0] = 0; else { memcpy(option, p, end - p); option[end - p] = 0; } /* parse value */ p = end + 1; if (*p == '{') { ++p; /* search "};" */ end = p; while ((end = (const char *) memchr(end, '}', connect_string_end - end)) != NULL) { if ((end + 1) != connect_string_end && end[1] == ';') break; ++end; } } else { end = (const char *) memchr(p, ';', connect_string_end - p); } if (!end) end = connect_string_end; if (!tds_dstr_copyn(&value, p, end - p)) return 0; if (strcasecmp(option, "SERVER") == 0) { /* ignore if servername specified */ if (!reparse) { dest_s = &connect_info->server_name; tds_lookup_host(tds_dstr_cstr(&value), tmp); if (!tds_dstr_copy(&connect_info->ip_addr, tmp)) { tds_dstr_free(&value); return 0; } } } else if (strcasecmp(option, "SERVERNAME") == 0) { if (!reparse) { tds_read_conf_file(connect_info, tds_dstr_cstr(&value)); reparse = 1; p = connect_string; continue; } } else if (strcasecmp(option, "DSN") == 0) { if (!reparse) { odbc_get_dsn_info(tds_dstr_cstr(&value), connect_info); reparse = 1; p = connect_string; continue; } } else if (strcasecmp(option, "DATABASE") == 0) { dest_s = &connect_info->database; } else if (strcasecmp(option, "UID") == 0) { dest_s = &connect_info->user_name; } else if (strcasecmp(option, "PWD") == 0) { dest_s = &connect_info->password; } else if (strcasecmp(option, "APP") == 0) { dest_s = &connect_info->app_name; } else if (strcasecmp(option, "WSID") == 0) { dest_s = &connect_info->host_name; } else if (strcasecmp(option, "LANGUAGE") == 0) { dest_s = &connect_info->language; } else if (strcasecmp(option, "Port") == 0) { connect_info->port = atoi(tds_dstr_cstr(&value)); } else if (strcasecmp(option, "TDS_Version") == 0) { tds_config_verstr(tds_dstr_cstr(&value), connect_info); } else if (strcasecmp(option, "Domain") == 0) { dest_s = &connect_info->default_domain; } else if (strcasecmp(option, "TextSize") == 0) { connect_info->text_size = atoi(tds_dstr_cstr(&value)); } else if (strcasecmp(option, "PacketSize") == 0) { connect_info->block_size = atoi(tds_dstr_cstr(&value)); /* TODO "Address" field */ } /* copy to destination */ if (dest_s) { tds_dstr_set(dest_s, tds_dstr_cstr(&value)); tds_dstr_init(&value); } p = end; /* handle "" ";.." "};.." cases */ if (p >= connect_string_end) break; if (*p == '}') ++p; ++p; } tds_dstr_free(&value); return p != NULL; }
DSTR* tds_dstr_dup(DSTR * s, const DSTR * src) { return tds_dstr_copyn(s, src->dstr_s, src->dstr_size); }
/** * copy a string from another * @param s dynamic string * @param src source buffer * @return string copied or NULL on memory error */ DSTR* tds_dstr_copy(DSTR * s, const char *src) { return tds_dstr_copyn(s, src, strlen(src)); }
/** * Parse connection string and fill login according * @param connect_string connect string * @param connect_string_end connect string end (pointer to char past last) * @param login where to store connection info * @return 1 if success 0 otherwhise */ int odbc_parse_connect_string(TDS_ERRS *errs, const char *connect_string, const char *connect_string_end, TDSLOGIN * login, TDS_PARSED_PARAM *parsed_params) { const char *p, *end; DSTR *dest_s, value = DSTR_INITIALIZER; enum { CFG_DSN = 1, CFG_SERVER = 2, CFG_SERVERNAME = 4 }; unsigned int cfgs = 0; /* flags for indicate second parse of string */ char option[24]; int trusted = 0; if (parsed_params) memset(parsed_params, 0, sizeof(*parsed_params)*ODBC_PARAM_SIZE); for (p = connect_string; p < connect_string_end && *p;) { int num_param = -1; dest_s = NULL; /* handle empty options */ while (p < connect_string_end && *p == ';') ++p; /* parse option */ end = (const char *) memchr(p, '=', connect_string_end - p); if (!end) break; /* account for spaces between ;'s. */ while (p < end && *p == ' ') ++p; if ((end - p) >= (int) sizeof(option)) option[0] = 0; else { memcpy(option, p, end - p); option[end - p] = 0; } /* parse value */ p = end + 1; if (*p == '{') { ++p; /* search "};" */ end = p; while ((end = (const char *) memchr(end, '}', connect_string_end - end)) != NULL) { if ((end + 1) != connect_string_end && end[1] == ';') break; ++end; } } else { end = (const char *) memchr(p, ';', connect_string_end - p); } if (!end) end = connect_string_end; if (!tds_dstr_copyn(&value, p, end - p)) { odbc_errs_add(errs, "HY001", NULL); return 0; } #define CHK_PARAM(p) (strcasecmp(option, odbc_param_##p) == 0 && (num_param=ODBC_PARAM_##p) >= 0) if (CHK_PARAM(Server)) { /* error if servername or DSN specified */ if ((cfgs & (CFG_DSN|CFG_SERVERNAME)) != 0) { tds_dstr_free(&value); odbc_errs_add(errs, "HY000", "Only one between SERVER, SERVERNAME and DSN can be specified"); return 0; } if (!cfgs) { dest_s = &login->server_name; /* not that safe cast but works -- freddy77 */ if (!parse_server(errs, (char *) tds_dstr_cstr(&value), login)) { tds_dstr_free(&value); return 0; } cfgs = CFG_SERVER; } } else if (CHK_PARAM(Servername)) { if ((cfgs & (CFG_DSN|CFG_SERVER)) != 0) { tds_dstr_free(&value); odbc_errs_add(errs, "HY000", "Only one between SERVER, SERVERNAME and DSN can be specified"); return 0; } if (!cfgs) { odbc_dstr_swap(&login->server_name, &value); tds_read_conf_file(login, tds_dstr_cstr(&login->server_name)); cfgs = CFG_SERVERNAME; p = connect_string; continue; } } else if (CHK_PARAM(DSN)) { if ((cfgs & (CFG_SERVER|CFG_SERVERNAME)) != 0) { tds_dstr_free(&value); odbc_errs_add(errs, "HY000", "Only one between SERVER, SERVERNAME and DSN can be specified"); return 0; } if (!cfgs) { if (!odbc_get_dsn_info(errs, tds_dstr_cstr(&value), login)) { tds_dstr_free(&value); return 0; } cfgs = CFG_DSN; p = connect_string; continue; } } else if (CHK_PARAM(Database)) { dest_s = &login->database; } else if (CHK_PARAM(UID)) { dest_s = &login->user_name; } else if (CHK_PARAM(PWD)) { dest_s = &login->password; } else if (CHK_PARAM(APP)) { dest_s = &login->app_name; } else if (CHK_PARAM(WSID)) { dest_s = &login->client_host_name; } else if (CHK_PARAM(Language)) { tds_parse_conf_section(TDS_STR_LANGUAGE, tds_dstr_cstr(&value), login); } else if (CHK_PARAM(Port)) { tds_parse_conf_section(TDS_STR_PORT, tds_dstr_cstr(&value), login); } else if (CHK_PARAM(TDS_Version)) { tds_parse_conf_section(TDS_STR_VERSION, tds_dstr_cstr(&value), login); } else if (CHK_PARAM(TextSize)) { tds_parse_conf_section(TDS_STR_TEXTSZ, tds_dstr_cstr(&value), login); } else if (CHK_PARAM(PacketSize)) { tds_parse_conf_section(TDS_STR_BLKSZ, tds_dstr_cstr(&value), login); } else if (CHK_PARAM(ClientCharset)) { tds_parse_conf_section(TDS_STR_CLCHARSET, tds_dstr_cstr(&value), login); } else if (CHK_PARAM(DumpFile)) { tds_parse_conf_section(TDS_STR_DUMPFILE, tds_dstr_cstr(&value), login); } else if (CHK_PARAM(DumpFileAppend)) { tds_parse_conf_section(TDS_STR_APPENDMODE, tds_dstr_cstr(&value), login); } else if (CHK_PARAM(DebugFlags)) { tds_parse_conf_section(TDS_STR_DEBUGFLAGS, tds_dstr_cstr(&value), login); } else if (CHK_PARAM(Encryption)) { tds_parse_conf_section(TDS_STR_ENCRYPTION, tds_dstr_cstr(&value), login); } else if (CHK_PARAM(UseNTLMv2)) { tds_parse_conf_section(TDS_STR_USENTLMV2, tds_dstr_cstr(&value), login); } else if (CHK_PARAM(REALM)) { tds_parse_conf_section(TDS_STR_REALM, tds_dstr_cstr(&value), login); } else if (CHK_PARAM(ServerSPN)) { tds_parse_conf_section(TDS_STR_SPN, tds_dstr_cstr(&value), login); } else if (CHK_PARAM(Trusted_Connection)) { trusted = tds_config_boolean(option, tds_dstr_cstr(&value), login); tdsdump_log(TDS_DBG_INFO1, "trusted %s -> %d\n", tds_dstr_cstr(&value), trusted); num_param = -1; /* TODO odbc_param_Address field */ } else if (CHK_PARAM(MARS_Connection)) { if (tds_config_boolean(option, tds_dstr_cstr(&value), login)) login->mars = 1; } else if (CHK_PARAM(AttachDbFilename)) { dest_s = &login->db_filename; } else if (CHK_PARAM(ApplicationIntent)) { const char *readonly_intent; if (strcasecmp(tds_dstr_cstr(&value), "ReadOnly") == 0) { readonly_intent = "yes"; } else if (strcasecmp(tds_dstr_cstr(&value), "ReadWrite") == 0) { readonly_intent = "no"; } else { tdsdump_log(TDS_DBG_ERROR, "Invalid ApplicationIntent %s\n", tds_dstr_cstr(&value)); return 0; } tds_parse_conf_section(TDS_STR_READONLY_INTENT, readonly_intent, login); tdsdump_log(TDS_DBG_INFO1, "Application Intent %s\n", readonly_intent); } if (num_param >= 0 && parsed_params) { parsed_params[num_param].p = p; parsed_params[num_param].len = end - p; } /* copy to destination */ if (dest_s) odbc_dstr_swap(dest_s, &value); p = end; /* handle "" ";.." "};.." cases */ if (p >= connect_string_end) break; if (*p == '}') ++p; ++p; } if (trusted) { if (parsed_params) { parsed_params[ODBC_PARAM_Trusted_Connection].p = "Yes"; parsed_params[ODBC_PARAM_Trusted_Connection].len = 3; parsed_params[ODBC_PARAM_UID].p = NULL; parsed_params[ODBC_PARAM_PWD].p = NULL; } tds_dstr_empty(&login->user_name); tds_dstr_empty(&login->password); } tds_dstr_free(&value); return 1; }