static SSL_RET tds_pull_func_login(SSL_PULL_ARGS) { TDSSOCKET *tds = (TDSSOCKET *) SSL_PTR; int have; tdsdump_log(TDS_DBG_INFO1, "in tds_pull_func_login\n"); /* here we are initializing (crypted inside TDS packets) */ /* if we have some data send it */ /* here MARS is not already initialized so test is correct */ /* TODO test even after initializing ?? */ if (tds->out_pos > 8) tds_flush_packet(tds); for(;;) { have = tds->in_len - tds->in_pos; tdsdump_log(TDS_DBG_INFO1, "have %d\n", have); assert(have >= 0); if (have > 0) break; tdsdump_log(TDS_DBG_INFO1, "before read\n"); if (tds_read_packet(tds) < 0) return -1; tdsdump_log(TDS_DBG_INFO1, "after read\n"); } if (len > have) len = have; tdsdump_log(TDS_DBG_INFO1, "read %lu bytes\n", (unsigned long int) len); memcpy(data, tds->in_buf + tds->in_pos, len); tds->in_pos += len; return len; }
static void unfinished_query_test(TDSSOCKET *tds) { int char_len; char *buf, *p; int i, len; union { TDS_USMALLINT si; TDS_UINT i; TDS_INT8 i8; char buf[8]; } conv; if (IS_TDS72_PLUS(tds->conn)) return; tds_init_write_buf(tds); /* try to build an invalid (unfinished) query split in two packets */ char_len = IS_TDS7_PLUS(tds->conn) ? 2 : 1; buf = calloc(1, tds->out_buf_max + 200); memset(buf, '-', tds->out_buf_max + 200); strcpy(buf + (tds->out_buf_max - 8) / char_len - strlen(select_query) + 1, select_query); memset(strchr(buf, 0), 0, 16); /* convert if needed */ len = strlen(buf); for (i = len; --i >= 0; ) { char c = buf[i]; buf[i * char_len + 0] = c; if (IS_TDS7_PLUS(tds->conn)) buf[i * char_len + 1] = 0; } len *= char_len; /* send the query using tds_put_int8, non allineati */ tds->out_flag = TDS_QUERY; if (tds_set_state(tds, TDS_WRITING) != TDS_WRITING) exit(1); p = buf; memcpy(conv.buf, p, 2); tds_put_smallint(tds, conv.si); p += 2; for (; p < buf + len; p += 8) { CHECK_TDS_EXTRA(tds); memcpy(conv.buf, p, 8); tds_put_int8(tds, conv.i8); } tds_flush_packet(tds); tds_set_state(tds, TDS_PENDING); /* check result was fine */ if (TDS_FAILED(tds_process_simple_query(tds))) { fprintf(stderr, "Error in prepared query\n"); exit(1); } free(buf); }
main(int argc, char **argv) { TDSSOCKET *tds; TDSLOGIN login; TDSRESULTINFO *resinfo; tds = tds_listen(atoi(argv[1])); /* get_incoming(tds->s); */ tds_read_login(tds, &login); dump_login(&login); if (!strcmp(login.user_name, "guest") && !strcmp(login.password, "sybase")) { tds->out_flag = 4; tds_env_change(tds, 1, "master", "pubs2"); tds_send_msg(tds, 5701, 2, 10, "Changed database context to 'pubs2'.", "JDBC", "ZZZZZ", 1); if (!login.suppress_language) { tds_env_change(tds, 2, NULL, "us_english"); tds_send_msg(tds, 5703, 1, 10, "Changed language setting to 'us_english'.", "JDBC", "ZZZZZ", 1); } tds_env_change(tds, 4, NULL, "512"); tds_send_login_ack(tds, "sql server"); tds_send_capabilities_token(tds); tds_send_253_token(tds, 0, 1); } else { /* send nack before exiting */ exit(1); } tds_flush_packet(tds); /* printf("incoming packet %d\n", tds_read_packet(tds)); */ printf("query : %s\n", tds_get_query(tds)); tds->out_flag = 4; resinfo = tds_alloc_results(1); resinfo->columns[0]->column_type = SYBVARCHAR; resinfo->columns[0]->column_size = 30; strcpy(resinfo->columns[0]->column_name, "name"); resinfo->columns[0]->column_namelen = 4; resinfo->current_row = "pubs2"; tds_send_result(tds, resinfo); tds_send_174_token(tds, 1); tds_send_row(tds, resinfo); tds_send_253_token(tds, 16, 1); tds_flush_packet(tds); sleep(30); }
static long tds_ssl_ctrl_login(BIO *b, int cmd, long num, void *ptr) { TDSSOCKET *tds = (TDSSOCKET *) b->ptr; switch (cmd) { case BIO_CTRL_FLUSH: if (tds->out_pos > 8) tds_flush_packet(tds); return 1; } return 0; }
static int tds_sspi_handle_next(TDSSOCKET * tds, struct tds_authentication * tds_auth, size_t len) { SecBuffer in_buf, out_buf; SecBufferDesc in_desc, out_desc; SECURITY_STATUS status; ULONG attrs; TimeStamp ts; TDS_UCHAR *auth_buf; TDSSSPIAUTH *auth = (TDSSSPIAUTH *) tds_auth; if (len < 32 || len > NTLMBUF_LEN) return TDS_FAIL; auth_buf = (TDS_UCHAR *) malloc(len); if (!auth_buf) return TDS_FAIL; tds_get_n(tds, auth_buf, (int)len); in_desc.ulVersion = out_desc.ulVersion = SECBUFFER_VERSION; in_desc.cBuffers = out_desc.cBuffers = 1; in_desc.pBuffers = &in_buf; out_desc.pBuffers = &out_buf; in_buf.BufferType = SECBUFFER_TOKEN; in_buf.pvBuffer = auth_buf; in_buf.cbBuffer = (ULONG)len; out_buf.BufferType = SECBUFFER_TOKEN; out_buf.pvBuffer = auth->tds_auth.packet; out_buf.cbBuffer = NTLMBUF_LEN; status = sec_fn->InitializeSecurityContextA(&auth->cred, &auth->cred_ctx, auth->sname, ISC_REQ_CONFIDENTIALITY | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONNECTION, 0, SECURITY_NETWORK_DREP, &in_desc, 0, &auth->cred_ctx, &out_desc, &attrs, &ts); free(auth_buf); if (status != SEC_E_OK) return TDS_FAIL; if (out_buf.cbBuffer == 0) return TDS_SUCCEED; tds_put_n(tds, auth->tds_auth.packet, out_buf.cbBuffer); return tds_flush_packet(tds); }
/* * if a dead connection on the client side left this member in a questionable * state, let's bring in a correct one * We are not sure what the client did so we must try to clean as much as * possible. * Use pool_free_member if the state is really broken. */ void pool_reset_member(TDS_POOL_MEMBER * pmbr) { // FIXME not wait for server !!! asyncronous TDSSOCKET *tds = pmbr->tds; if (pmbr->current_user) { pmbr->current_user->assigned_member = NULL; pool_free_user(pmbr->current_user); pmbr->current_user = NULL; } /* cancel whatever pending */ tds->state = TDS_IDLE; tds_init_write_buf(tds); tds->out_flag = TDS_CANCEL; tds_flush_packet(tds); tds->state = TDS_PENDING; if (tds_read_packet(tds) < 0) { pool_free_member(pmbr); return; } if (IS_TDS71_PLUS(tds->conn)) { /* this 0x9 final reset the state from mssql 2000 */ tds_init_write_buf(tds); tds->out_flag = TDS_QUERY; tds_write_packet(tds, 0x9); tds->state = TDS_PENDING; if (tds_read_packet(tds) < 0) { pool_free_member(pmbr); return; } } pmbr->state = TDS_IDLE; }
static TDSRET tds_gss_handle_next(TDSSOCKET * tds, struct tds_authentication * auth, size_t len) { TDSRET res; gss_buffer_desc recv_tok; if (((struct tds_gss_auth *) auth)->last_stat != GSS_S_CONTINUE_NEEDED) return TDS_FAIL; if (auth->packet) { OM_uint32 min_stat; gss_buffer_desc send_tok; send_tok.value = (void *) auth->packet; send_tok.length = auth->packet_len; gss_release_buffer(&min_stat, &send_tok); auth->packet = NULL; } recv_tok.length = len; recv_tok.value = (char* ) malloc(len); if (!recv_tok.value) return TDS_FAIL; tds_get_n(tds, recv_tok.value, len); res = tds_gss_continue(tds, (struct tds_gss_auth *) auth, &recv_tok); free(recv_tok.value); if (TDS_FAILED(res)) return res; if (auth->packet_len) { tds->out_flag = TDS7_AUTH; tds_put_n(tds, auth->packet, auth->packet_len); return tds_flush_packet(tds); } return TDS_SUCCESS; }
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; }
/* * 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; }
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; }
int main(int argc, char **argv) { TDSCONTEXT *ctx; TDSSOCKET *tds; TDSLOGIN *login; TDSRESULTINFO *resinfo; if (argc < 2 || atoi(argv[1]) <= 0) { fprintf(stderr, "syntax: %s <port>\n", argv[0]); return 1; } ctx = tds_alloc_context(NULL); tds = tds_listen(ctx, atoi(argv[1])); if (!tds) return 1; /* get_incoming(tds->s); */ login = tds_alloc_read_login(tds); if (!login) { fprintf(stderr, "Error reading login\n"); exit(1); } dump_login(login); if (!strcmp(tds_dstr_cstr(&login->user_name), "guest") && !strcmp(tds_dstr_cstr(&login->password), "sybase")) { tds->out_flag = TDS_REPLY; tds_env_change(tds, TDS_ENV_DATABASE, "master", "pubs2"); tds_send_msg(tds, 5701, 2, 10, "Changed database context to 'pubs2'.", "JDBC", "ZZZZZ", 1); if (!login->suppress_language) { tds_env_change(tds, TDS_ENV_LANG, NULL, "us_english"); tds_send_msg(tds, 5703, 1, 10, "Changed language setting to 'us_english'.", "JDBC", "ZZZZZ", 1); } tds_env_change(tds, TDS_ENV_PACKSIZE, NULL, "512"); /* TODO set mssql if tds7+ */ tds_send_login_ack(tds, "sql server"); if (IS_TDS50(tds)) tds_send_capabilities_token(tds); tds_send_done_token(tds, 0, 1); } else { /* send nack before exiting */ exit(1); } tds_flush_packet(tds); tds_free_login(login); login = NULL; /* printf("incoming packet %d\n", tds_read_packet(tds)); */ printf("query : %s\n", tds_get_generic_query(tds)); tds->out_flag = TDS_REPLY; resinfo = tds_alloc_results(1); resinfo->columns[0]->column_type = SYBVARCHAR; resinfo->columns[0]->column_size = 30; strcpy(resinfo->columns[0]->column_name, "name"); resinfo->columns[0]->column_namelen = 4; resinfo->current_row = (TDS_UCHAR*) "pubs2"; resinfo->columns[0]->column_data = resinfo->current_row; tds_send_result(tds, resinfo); tds_send_control_token(tds, 1); tds_send_row(tds, resinfo); tds_send_done_token(tds, 16, 1); tds_flush_packet(tds); sleep(30); tds_free_results(resinfo); tds_free_socket(tds); tds_free_context(ctx); return 0; }