login.c
来自「在Linux/Unix下面访问WINDOWS SQLSERVER 的ODBC驱动」· C语言 代码 · 共 1,031 行 · 第 1/2 页
C
1,031 行
*/ /* * This is the original capabilities packet we were working with (sqsh) * unsigned char capabilities[]= {0x01,0x07,0x03,109,127,0xFF,0xFF,0xFF,0xFE,0x02,0x07,0x00,0x00,0x0A,104,0x00,0x00,0x00}; * original with 4.x messages * unsigned char capabilities[]= {0x01,0x07,0x03,109,127,0xFF,0xFF,0xFF,0xFE,0x02,0x07,0x00,0x00,0x00,120,192,0x00,0x0D}; * This is isql 11.0.3 * unsigned char capabilities[]= {0x01,0x07,0x00,96, 129,207, 0xFF,0xFE,62, 0x02,0x07,0x00,0x00,0x00,120,192,0x00,0x0D}; * like isql but with 5.0 messages * unsigned char capabilities[]= {0x01,0x07,0x00,96, 129,207, 0xFF,0xFE,62, 0x02,0x07,0x00,0x00,0x00,120,192,0x00,0x00}; */ unsigned char protocol_version[4]; unsigned char program_version[4]; const char *server_charset; int len; char blockstr[16]; if (strchr(tds_dstr_cstr(&connection->user_name), '\\') != NULL) { tdsdump_log(TDS_DBG_ERROR, "NT login not support using TDS 4.x or 5.0\n"); return TDS_FAIL; } if (IS_TDS42(tds)) { memcpy(protocol_version, "\004\002\000\000", 4); memcpy(program_version, "\004\002\000\000", 4); } else if (IS_TDS46(tds)) { memcpy(protocol_version, "\004\006\000\000", 4); memcpy(program_version, "\004\002\000\000", 4); } else if (IS_TDS50(tds)) { memcpy(protocol_version, "\005\000\000\000", 4); memcpy(program_version, "\005\000\000\000", 4); } else { tdsdump_log(TDS_DBG_SEVERE, "Unknown protocol version!\n"); exit(1); } /* * the following code is adapted from Arno Pedusaar's * (psaar@fenar.ee) MS-SQL Client. His was a much better way to * do this, (well...mine was a kludge actually) so here's mostly his */ tds_put_login_string(tds, tds_dstr_cstr(&connection->client_host_name), TDS_MAX_LOGIN_STR_SZ); /* client host name */ tds_put_login_string(tds, tds_dstr_cstr(&connection->user_name), TDS_MAX_LOGIN_STR_SZ); /* account name */ tds_put_login_string(tds, tds_dstr_cstr(&connection->password), TDS_MAX_LOGIN_STR_SZ); /* account password */ tds_put_login_string(tds, "37876", TDS_MAX_LOGIN_STR_SZ); /* host process */#ifdef WORDS_BIGENDIAN if (tds->emul_little_endian) { tds_put_n(tds, le1, 6); } else { tds_put_n(tds, be1, 6); }#else tds_put_n(tds, le1, 6);#endif tds_put_byte(tds, connection->bulk_copy); tds_put_n(tds, magic2, 2); if (IS_TDS42(tds)) { tds_put_int(tds, 512); } else { tds_put_int(tds, 0); } tds_put_n(tds, magic3, 3); tds_put_login_string(tds, tds_dstr_cstr(&connection->app_name), TDS_MAX_LOGIN_STR_SZ); tds_put_login_string(tds, tds_dstr_cstr(&connection->server_name), TDS_MAX_LOGIN_STR_SZ); if (IS_TDS42(tds)) { tds_put_login_string(tds, tds_dstr_cstr(&connection->password), 255); } else { len = tds_dstr_len(&connection->password); if (len > 253) len = 0; tds_put_byte(tds, 0); tds_put_byte(tds, len); tds_put_n(tds, tds_dstr_cstr(&connection->password), len); tds_put_n(tds, NULL, 253 - len); tds_put_byte(tds, len + 2); } tds_put_n(tds, protocol_version, 4); /* TDS version; { 0x04,0x02,0x00,0x00 } */ tds_put_login_string(tds, tds_dstr_cstr(&connection->library), 10); /* client program name */ if (IS_TDS42(tds)) { tds_put_int(tds, 0); } else { tds_put_n(tds, program_version, 4); /* program version ? */ }#ifdef WORDS_BIGENDIAN if (tds->emul_little_endian) { tds_put_n(tds, le2, 3); } else { tds_put_n(tds, be2, 3); }#else tds_put_n(tds, le2, 3);#endif tds_put_login_string(tds, tds_dstr_cstr(&connection->language), TDS_MAX_LOGIN_STR_SZ); /* language */ tds_put_byte(tds, connection->suppress_language); tds_put_n(tds, magic5, 2); tds_put_byte(tds, connection->encryption_level ? 1 : 0); tds_put_n(tds, magic6, 10); /* use charset nearest to client or nothing */ server_charset = NULL; if (!tds_dstr_isempty(&connection->server_charset)) server_charset = tds_dstr_cstr(&connection->server_charset); else server_charset = tds_sybase_charset_name(tds_dstr_cstr(&connection->client_charset)); if (!server_charset) server_charset = ""; tds_put_login_string(tds, server_charset, TDS_MAX_LOGIN_STR_SZ); /* charset */ /* this is a flag, mean that server should use character set provided by client */ /* TODO notify charset change ?? what's correct meaning ?? -- freddy77 */ tds_put_byte(tds, 1); /* network packet size */ if (connection->block_size < 1000000 && connection->block_size) sprintf(blockstr, "%d", connection->block_size); else strcpy(blockstr, "512"); tds_put_login_string(tds, blockstr, 6); if (IS_TDS42(tds)) { tds_put_n(tds, magic42, 8); } else if (IS_TDS46(tds)) { tds_put_n(tds, magic42, 4); } else if (IS_TDS50(tds)) { tds_put_n(tds, magic50, 4); tds_put_byte(tds, TDS_CAPABILITY_TOKEN); tds_put_smallint(tds, TDS_MAX_CAPABILITY); tds_put_n(tds, tds->capabilities, TDS_MAX_CAPABILITY); } return tds_flush_packet(tds);}/** * tds7_send_login() -- Send a TDS 7.0 login packet * TDS 7.0 login packet is vastly different and so gets its own function * \returns the return value is ignored by the caller. :-/ */static inttds7_send_login(TDSSOCKET * tds, TDSCONNECTION * connection){ int rc; static const unsigned char client_progver[] = { 6, 0x83, 0xf2, 0xf8 }; static const unsigned char tds7Version[] = { 0x00, 0x00, 0x00, 0x70 }; static const unsigned char tds8Version[] = { 0x01, 0x00, 0x00, 0x71 }; static const unsigned char tds9Version[] = { 0x02, 0x00, 0x09, 0x72 }; static const unsigned char connection_id[] = { 0x00, 0x00, 0x00, 0x00 }; unsigned char option_flag1 = 0x00; unsigned char option_flag2 = tds->option_flag2; static const unsigned char sql_type_flag = 0x00; static const unsigned char reserved_flag = 0x00; static const unsigned char time_zone[] = { 0x88, 0xff, 0xff, 0xff }; static const unsigned char collation[] = { 0x36, 0x04, 0x00, 0x00 }; unsigned char hwaddr[6]; /* 0xb4,0x00,0x30,0x00,0xe4,0x00,0x00,0x00; */ char unicode_string[256]; char *punicode; size_t unicode_left; int packet_size; int block_size; int current_pos; const char *user_name = tds_dstr_cstr(&connection->user_name); int user_name_len = strlen(user_name); int host_name_len = tds_dstr_len(&connection->client_host_name); int app_name_len = tds_dstr_len(&connection->app_name); size_t password_len = tds_dstr_len(&connection->password); int server_name_len = tds_dstr_len(&connection->server_name); int library_len = tds_dstr_len(&connection->library); int language_len = tds_dstr_len(&connection->language); int database_len = tds_dstr_len(&connection->database); int auth_len = 0; tds->out_flag = TDS7_LOGIN; /* discard possible previous authentication */ if (tds->authentication) { tds->authentication->free(tds, tds->authentication); tds->authentication = NULL; } /* avoid overflow limiting password */ if (password_len > 128) password_len = 128; current_pos = IS_TDS90(tds) ? 86 + 8 : 86; /* ? */ packet_size = current_pos + (host_name_len + app_name_len + server_name_len + library_len + language_len + database_len) * 2; /* check ntlm */ if (strchr(user_name, '\\') != NULL) { tds->authentication = tds_ntlm_get_auth(tds); if (!tds->authentication) return TDS_FAIL; auth_len = tds->authentication->packet_len; packet_size += auth_len; } else if (user_name_len == 0) {#ifdef ENABLE_KRB5 /* try kerberos */ tds->authentication = tds_gss_get_auth(tds); if (!tds->authentication) return TDS_FAIL; auth_len = tds->authentication->packet_len; packet_size += auth_len;#else return TDS_FAIL;#endif } else packet_size += (user_name_len + password_len) * 2; tdsdump_log(TDS_DBG_INFO2, "quietly sending TDS 7+ login packet\n"); tdsdump_off(); tds_put_int(tds, packet_size); if (IS_TDS90(tds)) { tds_put_n(tds, tds9Version, 4); } else if (IS_TDS8_PLUS(tds)) { tds_put_n(tds, tds8Version, 4); } else { tds_put_n(tds, tds7Version, 4); } if (connection->block_size < 1000000 && connection->block_size >= 512) block_size = connection->block_size; else block_size = 4096; /* SQL server default */ tds_put_int(tds, block_size); /* desired packet size being requested by client */ if (block_size > tds->env.block_size) tds_realloc_socket(tds, block_size); tds_put_n(tds, client_progver, 4); /* client program version ? */ tds_put_int(tds, getpid()); /* process id of this process */ tds_put_n(tds, connection_id, 4); option_flag1 |= 0x80; /* enable warning messages if SET LANGUAGE issued */ option_flag1 |= 0x40; /* change to initial database must succeed */ option_flag1 |= 0x20; /* enable warning messages if USE <database> issued */ tds_put_byte(tds, option_flag1); if (tds->authentication) option_flag2 |= 0x80; /* enable domain login security */ tds_put_byte(tds, option_flag2); tds_put_byte(tds, sql_type_flag); tds_put_byte(tds, reserved_flag); tds_put_n(tds, time_zone, 4); tds_put_n(tds, collation, 4); /* host name */ tds_put_smallint(tds, current_pos); tds_put_smallint(tds, host_name_len); current_pos += host_name_len * 2; if (tds->authentication) { tds_put_smallint(tds, 0); tds_put_smallint(tds, 0); tds_put_smallint(tds, 0); tds_put_smallint(tds, 0); } else { /* username */ tds_put_smallint(tds, current_pos); tds_put_smallint(tds, user_name_len); current_pos += user_name_len * 2; /* password */ tds_put_smallint(tds, current_pos); tds_put_smallint(tds, password_len); current_pos += password_len * 2; } /* app name */ tds_put_smallint(tds, current_pos); tds_put_smallint(tds, app_name_len); current_pos += app_name_len * 2; /* server name */ tds_put_smallint(tds, current_pos); tds_put_smallint(tds, server_name_len); current_pos += server_name_len * 2; /* unknown */ tds_put_smallint(tds, 0); tds_put_smallint(tds, 0); /* library name */ tds_put_smallint(tds, current_pos); tds_put_smallint(tds, library_len); current_pos += library_len * 2; /* language - kostya@warmcat.excom.spb.su */ tds_put_smallint(tds, current_pos); tds_put_smallint(tds, language_len); current_pos += language_len * 2; /* database name */ tds_put_smallint(tds, current_pos); tds_put_smallint(tds, database_len); current_pos += database_len * 2; /* MAC address */ tds_getmac(tds->s, hwaddr); tds_put_n(tds, hwaddr, 6); /* authentication stuff */ tds_put_smallint(tds, current_pos); tds_put_smallint(tds, auth_len); /* this matches numbers at end of packet */ current_pos += auth_len; /* unknown */ tds_put_smallint(tds, current_pos); tds_put_smallint(tds, 0); if (IS_TDS90(tds)) { tds_put_smallint(tds, current_pos); tds_put_smallint(tds, 0); tds_put_int(tds, 0); } /* FIXME here we assume single byte, do not use *2 to compute bytes, convert before !!! */ tds_put_string(tds, tds_dstr_cstr(&connection->client_host_name), host_name_len); if (!tds->authentication) { const char *p; TDSICONV *char_conv = tds->char_convs[client2ucs2]; tds_put_string(tds, tds_dstr_cstr(&connection->user_name), user_name_len); p = tds_dstr_cstr(&connection->password); punicode = unicode_string; unicode_left = sizeof(unicode_string); memset(&char_conv->suppress, 0, sizeof(char_conv->suppress)); if (tds_iconv(tds, tds->char_convs[client2ucs2], to_server, &p, &password_len, &punicode, &unicode_left) == (size_t) - 1) { tdsdump_log(TDS_DBG_INFO1, "password \"%s\" could not be converted to UCS-2\n", p); assert(0); } password_len = punicode - unicode_string; tds7_crypt_pass((unsigned char *) unicode_string, password_len, (unsigned char *) unicode_string); tds_put_n(tds, unicode_string, password_len); } tds_put_string(tds, tds_dstr_cstr(&connection->app_name), app_name_len); tds_put_string(tds, tds_dstr_cstr(&connection->server_name), server_name_len); tds_put_string(tds, tds_dstr_cstr(&connection->library), library_len); tds_put_string(tds, tds_dstr_cstr(&connection->language), language_len); tds_put_string(tds, tds_dstr_cstr(&connection->database), database_len); if (tds->authentication) tds_put_n(tds, tds->authentication->packet, auth_len); rc = tds_flush_packet(tds); tdsdump_on(); return rc;}/** * tds7_crypt_pass() -- 'encrypt' TDS 7.0 style passwords. * the calling function is responsible for ensuring crypt_pass is at least * 'len' characters */unsigned char *tds7_crypt_pass(const unsigned char *clear_pass, int len, unsigned char *crypt_pass){ int i; for (i = 0; i < len; i++) crypt_pass[i] = ((clear_pass[i] << 4) | (clear_pass[i] >> 4)) ^ 0xA5; return crypt_pass;}static inttds8_do_login(TDSSOCKET * tds, TDSCONNECTION * connection){#if !defined(HAVE_GNUTLS) && !defined(HAVE_OPENSSL) /* * In case we do not have SSL enabled do not send pre-login so * if server has certificate but no force encryption login success */ return tds7_send_login(tds, connection);#else int i, len, ret; const char *instance_name = tds_dstr_isempty(&connection->instance_name) ? "MSSQLServer" : tds_dstr_cstr(&connection->instance_name); int instance_name_len = strlen(instance_name) + 1; TDS_CHAR crypt_flag; unsigned int start_pos = 21;#define START_POS 21#define UI16BE(n) ((n) >> 8), ((n) & 0xffu)#define SET_UI16BE(i,n) do { buf[i] = ((n) >> 8); buf[i+1] = ((n) & 0xffu); } while(0) TDS_UCHAR buf[] = { /* netlib version */ 0, UI16BE(START_POS), UI16BE(6), /* encryption */ 1, UI16BE(START_POS + 6), UI16BE(1), /* instance */ 2, UI16BE(START_POS + 6 + 1), UI16BE(0), /* process id */ 3, UI16BE(0), UI16BE(4), /* ???? unknown ??? */ 4, UI16BE(0), UI16BE(1), /* end */ 0xff }; static const TDS_UCHAR netlib8[] = { 8, 0, 1, 0x55, 0, 0 }; static const TDS_UCHAR netlib9[] = { 9, 0, 0, 0, 0, 0 }; TDS_UCHAR *p; SET_UI16BE(13, instance_name_len); if (!IS_TDS90(tds)) { SET_UI16BE(16, START_POS + 6 + 1 + instance_name_len); buf[20] = 0xff; } else { start_pos += 5;#undef START_POS#define START_POS 26 SET_UI16BE(1, START_POS); SET_UI16BE(6, START_POS + 6); SET_UI16BE(11, START_POS + 6 + 1); SET_UI16BE(16, START_POS + 6 + 1 + instance_name_len); SET_UI16BE(21, START_POS + 6 + 1 + instance_name_len + 4); } assert(start_pos >= 21 && start_pos <= sizeof(buf)); assert(buf[start_pos-1] == 0xff); /* do prelogin */ tds->out_flag = TDS8_PRELOGIN; tds_put_n(tds, buf, start_pos); /* netlib version */ tds_put_n(tds, IS_TDS90(tds) ? netlib9 : netlib8, 6); /* encryption */ tds_put_byte(tds, connection->encryption_level ? 1 : 0); /* instance */ tds_put_n(tds, instance_name, instance_name_len); /* pid */ tds_put_int(tds, getpid()); /* ???? unknown ??? */ if (IS_TDS90(tds)) tds_put_byte(tds, 0); if (tds_flush_packet(tds) == TDS_FAIL) return TDS_FAIL; /* now process reply from server */ len = tds_read_packet(tds); if (len <= 0 || tds->in_flag != 4) return TDS_FAIL; len = tds->in_len - tds->in_pos; /* the only thing we care is flag */ p = tds->in_buf + tds->in_pos; /* default 2, no certificate, no encryption */ crypt_flag = 2; for (i = 0;; i += 5) { TDS_UCHAR type; int off, l; if (i >= len) return TDS_FAIL; type = p[i]; if (type == 0xff) break; /* check packet */ if (i+4 >= len) return TDS_FAIL; off = (((int) p[i+1]) << 8) | p[i+2]; l = (((int) p[i+3]) << 8) | p[i+4]; if (off > len || (off+l) > len) return TDS_FAIL; if (type == 1 && l >= 1) { crypt_flag = p[off]; } } /* we readed all packet */ tds->in_pos += len; /* TODO some mssql version do not set last packet, update tds according */ tdsdump_log(TDS_DBG_INFO1, "detected flag %d\n", crypt_flag); /* if server do not has certificate do normal login */ if (crypt_flag == 2) { /* unless we wanted encryption and got none, then fail */ if (connection->encryption_level >= TDS_ENCRYPTION_REQUIRE) return TDS_FAIL; return tds7_send_login(tds, connection); } /* * if server has a certificate it require at least a crypted login * (even if data is not encrypted) */ /* here we have to do encryption ... */ if (tds_ssl_init(tds) != TDS_SUCCEED) return TDS_FAIL; ret = tds7_send_login(tds, connection); /* if flag is 0 it means that after login server continue not encrypted */ if (crypt_flag == 0 || ret != TDS_SUCCEED) tds_ssl_deinit(tds); return ret;#endif}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?