⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 challenge.c

📁 在Linux/Unix下面访问WINDOWS SQLSERVER 的ODBC驱动程序
💻 C
字号:
/* FreeTDS - Library of routines accessing Sybase and Microsoft databases * Copyright (C) 1998-1999  Brian Bruns * Copyright (C) 2005  Frediano Ziglio * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */#if HAVE_CONFIG_H#include <config.h>#endif#if HAVE_STDLIB_H#include <stdlib.h>#endif /* HAVE_STDLIB_H */#include <ctype.h>#if HAVE_STRING_H#include <string.h>#endif /* HAVE_STRING_H */#include "tds.h"#include "tdsbytes.h"#include "tdsstring.h"#include "md4.h"#include "md5.h"#include "des.h"#ifdef DMALLOC#include <dmalloc.h>#endifTDS_RCSID(var, "$Id: challenge.c,v 1.30 2007/11/26 06:25:11 freddy77 Exp $");/** * \ingroup libtds * \defgroup auth Authentication * Functions for handling authentication. *//** * \addtogroup auth * @{  *//* * The following code is based on some psuedo-C code from ronald@innovation.ch */typedef struct tds_answer{	unsigned char lm_resp[24];	unsigned char nt_resp[24];} TDSANSWER;static void tds_answer_challenge(const char *passwd, const unsigned char *challenge, TDS_UINT *flags, TDSANSWER * answer);static void tds_encrypt_answer(const unsigned char *hash, const unsigned char *challenge, unsigned char *answer);static void tds_convert_key(const unsigned char *key_56, DES_KEY * ks);/** * Crypt a given password using schema required for NTLMv1 or NTLM2 authentication * @param passwd clear text domain password * @param challenge challenge data given by server * @param flags NTLM flags from server side * @param answer buffer where to store crypted password */static voidtds_answer_challenge(const char *passwd, const unsigned char *challenge, TDS_UINT *flags, TDSANSWER * answer){#define MAX_PW_SZ 14	int len;	int i;	static const des_cblock magic = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };	DES_KEY ks;	unsigned char hash[24], ntlm2_challenge[16];	unsigned char passwd_buf[256];	MD4_CTX context;	memset(answer, 0, sizeof(TDSANSWER));	if (!(*flags & 0x80000)) {		/* convert password to upper and pad to 14 chars */		memset(passwd_buf, 0, MAX_PW_SZ);		len = strlen(passwd);		if (len > MAX_PW_SZ)			len = MAX_PW_SZ;		for (i = 0; i < len; i++)			passwd_buf[i] = toupper((unsigned char) passwd[i]);		/* hash the first 7 characters */		tds_convert_key(passwd_buf, &ks);		tds_des_ecb_encrypt(&magic, sizeof(magic), &ks, (hash + 0));		/* hash the second 7 characters */		tds_convert_key(passwd_buf + 7, &ks);		tds_des_ecb_encrypt(&magic, sizeof(magic), &ks, (hash + 8));		memset(hash + 16, 0, 5);		tds_encrypt_answer(hash, challenge, answer->lm_resp);	} else {		MD5_CTX md5_ctx;		/* NTLM2 */		/* TODO find a better random... */		for (i = 0; i < 8; ++i)			hash[i] = rand() / (RAND_MAX/256);		memset(hash + 8, 0, 16);		memcpy(answer->lm_resp, hash, 24);		MD5Init(&md5_ctx);		MD5Update(&md5_ctx, challenge, 8);		MD5Update(&md5_ctx, hash, 8);		MD5Final(&md5_ctx, ntlm2_challenge);		challenge = ntlm2_challenge;		memset(&md5_ctx, 0, sizeof(md5_ctx));	}	*flags = 0x8201;	/* NTLM/NTLM2 response */	len = strlen(passwd);	if (len > 128)		len = 128;	/*	 * TODO we should convert this to ucs2le instead of	 * using it blindly as iso8859-1	 */	for (i = 0; i < len; ++i) {		passwd_buf[2 * i] = passwd[i];		passwd_buf[2 * i + 1] = 0;	}	/* compute NTLM hash */	MD4Init(&context);	MD4Update(&context, passwd_buf, len * 2);	MD4Final(&context, hash);	memset(hash + 16, 0, 5);	tds_encrypt_answer(hash, challenge, answer->nt_resp);	/* with security is best be pedantic */	memset(&ks, 0, sizeof(ks));	memset(hash, 0, sizeof(hash));	memset(passwd_buf, 0, sizeof(passwd_buf));	memset(ntlm2_challenge, 0, sizeof(ntlm2_challenge));	memset(&context, 0, sizeof(context));}/** takes a 21 byte array and treats it as 3 56-bit DES keys. The* 8 byte plaintext is encrypted with each key and the resulting 24* bytes are stored in the results array.*/static voidtds_encrypt_answer(const unsigned char *hash, const unsigned char *challenge, unsigned char *answer){	DES_KEY ks;	tds_convert_key(hash, &ks);	tds_des_ecb_encrypt(challenge, 8, &ks, answer);	tds_convert_key(&hash[7], &ks);	tds_des_ecb_encrypt(challenge, 8, &ks, &answer[8]);	tds_convert_key(&hash[14], &ks);	tds_des_ecb_encrypt(challenge, 8, &ks, &answer[16]);	memset(&ks, 0, sizeof(ks));}/** turns a 56 bit key into the 64 bit, odd parity key and sets the key.* The key schedule ks is also set.*/static voidtds_convert_key(const unsigned char *key_56, DES_KEY * ks){	des_cblock key;	key[0] = key_56[0];	key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);	key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);	key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);	key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);	key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);	key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);	key[7] = (key_56[6] << 1) & 0xFF;	tds_des_set_odd_parity(key);	tds_des_set_key(ks, key, sizeof(key));	memset(&key, 0, sizeof(key));}static inttds7_send_auth(TDSSOCKET * tds, const unsigned char *challenge, TDS_UINT flags){	int current_pos;	TDSANSWER answer;	/* FIXME: stuff duplicate in tds7_send_login */	const char *domain;	const char *user_name;	const char *p;	int user_name_len;	int host_name_len;	int password_len;	int domain_len;	TDSCONNECTION *connection = tds->connection;	/* check connection */	if (!connection)		return TDS_FAIL;	/* parse a bit of config */	user_name = tds_dstr_cstr(&connection->user_name);	user_name_len = user_name ? strlen(user_name) : 0;	host_name_len = tds_dstr_len(&connection->client_host_name);	password_len = tds_dstr_len(&connection->password);	/* parse domain\username */	if ((p = strchr(user_name, '\\')) == NULL)		return TDS_FAIL;	domain = user_name;	domain_len = p - user_name;	user_name = p + 1;	user_name_len = strlen(user_name);	tds->out_flag = TDS7_AUTH;	tds_put_n(tds, "NTLMSSP", 8);	tds_put_int(tds, 3);	/* sequence 3 */	/* FIXME *2 work only for single byte encodings */	current_pos = 64 + (domain_len + user_name_len + host_name_len) * 2;	tds_put_smallint(tds, 24);	/* lan man resp length */	tds_put_smallint(tds, 24);	/* lan man resp length */	tds_put_int(tds, current_pos);	/* resp offset */	current_pos += 24;	tds_put_smallint(tds, 24);	/* nt resp length */	tds_put_smallint(tds, 24);	/* nt resp length */	tds_put_int(tds, current_pos);	/* nt resp offset */	current_pos = 64;	/* domain */	tds_put_smallint(tds, domain_len * 2);	tds_put_smallint(tds, domain_len * 2);	tds_put_int(tds, current_pos);	current_pos += domain_len * 2;	/* username */	tds_put_smallint(tds, user_name_len * 2);	tds_put_smallint(tds, user_name_len * 2);	tds_put_int(tds, current_pos);	current_pos += user_name_len * 2;	/* hostname */	tds_put_smallint(tds, host_name_len * 2);	tds_put_smallint(tds, host_name_len * 2);	tds_put_int(tds, current_pos);	current_pos += host_name_len * 2;	/* unknown */	tds_put_smallint(tds, 0);	tds_put_smallint(tds, 0);	tds_put_int(tds, current_pos + (24 * 2));	/* flags */	tds_answer_challenge(tds_dstr_cstr(&connection->password), challenge, &flags, &answer);	tds_put_int(tds, flags);	tds_put_string(tds, domain, domain_len);	tds_put_string(tds, user_name, user_name_len);	tds_put_string(tds, tds_dstr_cstr(&connection->client_host_name), host_name_len);	tds_put_n(tds, answer.lm_resp, 24);	tds_put_n(tds, answer.nt_resp, 24);	/* for security reason clear structure */	memset(&answer, 0, sizeof(TDSANSWER));	return tds_flush_packet(tds);}typedef struct tds_ntlm_auth{	TDSAUTHENTICATION tds_auth;} TDSNTLMAUTH;static inttds_ntlm_free(TDSSOCKET * tds, TDSAUTHENTICATION * tds_auth){	TDSNTLMAUTH *auth = (TDSNTLMAUTH *) tds_auth;	free(auth->tds_auth.packet);	free(auth);	return TDS_SUCCEED;}static const unsigned char ntlm_id[] = "NTLMSSP";static inttds_ntlm_handle_next(TDSSOCKET * tds, struct tds_authentication * auth, size_t len){	unsigned char nonce[8];	TDS_UINT flags;	int where;	/* at least 32 bytes (till context) */	if (len < 32)		return TDS_FAIL;	tds_get_n(tds, nonce, 8);	/* NTLMSSP\0 */	if (memcmp(nonce, ntlm_id, 8) != 0)		return TDS_FAIL;	if (tds_get_int(tds) != 2)	/* sequence -> 2 */		return TDS_FAIL;	tds_get_n(tds, NULL, 4);	/* domain len (2 time) */	tds_get_int(tds);	/* domain offset */	flags = tds_get_int(tds);	/* flags */	tds_get_n(tds, nonce, 8);	tdsdump_dump_buf(TDS_DBG_INFO1, "TDS_AUTH_TOKEN nonce", nonce, 8);	where = 32;	/*	 * tds_get_string(tds, domain, domain_len); 	 * tdsdump_log(TDS_DBG_INFO1, "TDS_AUTH_TOKEN domain %s\n", domain);	 * where += strlen(domain);	 */	/* discard context, target and data informations */	tds_get_n(tds, NULL, len - where);	tdsdump_log(TDS_DBG_INFO1, "Draining %d bytes\n", (int) (len - where));	return tds7_send_auth(tds, nonce, flags);}/** * Build a NTLMSPP packet to send to server * @param tds     A pointer to the TDSSOCKET structure managing a client/server operation. * @return authentication info */TDSAUTHENTICATION * tds_ntlm_get_auth(TDSSOCKET * tds){	const char *domain;	const char *user_name;	const char *p;	TDS_UCHAR *packet;	int host_name_len;	int domain_len;	int auth_len;	struct tds_ntlm_auth *auth;	if (!tds->connection)		return NULL;	user_name = tds_dstr_cstr(&tds->connection->user_name);	host_name_len = tds_dstr_len(&tds->connection->client_host_name);	/* check override of domain */	if ((p = strchr(user_name, '\\')) == NULL)		return NULL;	domain = user_name;	domain_len = p - user_name;	auth = (struct tds_ntlm_auth *) calloc(1, sizeof(struct tds_ntlm_auth));	if (!auth)		return NULL;	auth->tds_auth.free = tds_ntlm_free;	auth->tds_auth.handle_next = tds_ntlm_handle_next;	auth->tds_auth.packet_len = auth_len = 32 + host_name_len + domain_len;	auth->tds_auth.packet = packet = malloc(auth_len);	if (!packet) {		free(auth);		return NULL;	}	/* built NTLMSSP authentication packet */	memcpy(packet, ntlm_id, 8);	/* sequence 1 client -> server */	TDS_PUT_A4LE(packet + 8, 1);	/* flags */	TDS_PUT_A4LE(packet + 12, 0x08b201);	/* domain info */	TDS_PUT_A2LE(packet + 16, domain_len);	TDS_PUT_A2LE(packet + 18, domain_len);	TDS_PUT_A4LE(packet + 20, 32 + host_name_len);	/* hostname info */	TDS_PUT_A2LE(packet + 24, host_name_len);	TDS_PUT_A2LE(packet + 26, host_name_len);	TDS_PUT_A4LE(packet + 28, 32);	/*	 * here XP put version like 05 01 28 0a (5.1.2600),	 * similar to GetVersion result	 * and some unknown bytes like 00 00 00 0f	 */	/* hostname and domain */	memcpy(packet + 32, tds_dstr_cstr(&tds->connection->client_host_name), host_name_len);	memcpy(packet + 32 + host_name_len, domain, domain_len);	return (TDSAUTHENTICATION *) auth;}/** @} */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -