Beispiel #1
0
/**
 * Get N bytes from the buffer and return them in the already allocated space  
 * given to us.  We ASSUME that the person calling this function has done the  
 * bounds checking for us since they know how many bytes they want here.
 * dest of NULL means we just want to eat the bytes.   ([email protected])
 */
void *
tds_get_n(TDSSOCKET * tds, void *dest, int need)
{
	assert(need >= 0);

	for (;;) {
		int have = tds->in_len - tds->in_pos;

		if (need <= have)
			break;
		/* We need more than is in the buffer, copy what is there */
		if (dest != NULL) {
			memcpy((char *) dest, tds->in_buf + tds->in_pos, have);
			dest = (char *) dest + have;
		}
		need -= have;
		if (tds_read_packet(tds) < 0)
			return NULL;
	}
	if (need > 0) {
		/* get the remainder if there is any */
		if (dest != NULL) {
			memcpy((char *) dest, tds->in_buf + tds->in_pos, need);
		}
		tds->in_pos += need;
	}
	return dest;
}
Beispiel #2
0
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;
}
Beispiel #3
0
/*
** Return a single byte from the input buffer
*/
unsigned char
tds_get_byte(TDSSOCKET * tds)
{
	while (tds->in_pos >= tds->in_len) {
		if (tds_read_packet(tds) < 0)
			return 0;
	}
	return tds->in_buf[tds->in_pos++];
}
Beispiel #4
0
/*
 * 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;
}
Beispiel #5
0
/*
** Return a single byte from the input buffer
*/
unsigned char
tds_get_byte(TDSSOCKET * tds)
{
	int rc;

	if (tds->in_pos >= tds->in_len) {
		do {
			if (IS_TDSDEAD(tds) || (rc = tds_read_packet(tds)) < 0)
				return 0;
		} while (!rc);
	}
	return tds->in_buf[tds->in_pos++];
}
Beispiel #6
0
/*
 * 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;
}
Beispiel #7
0
/**
 * Read a query, and return it as an ASCII string with a \0 terminator.  This
 * should work for TDS4, TDS5, and TDS7+ connections.  Also, it converts RPC
 * calls into stored procedure queries, and it skips CANCEL packets.  The query
 * string is returned in a static buffer which is overwritten each time this
 * function is called.
 * \param tds  The socket to read from.
 * \return A query string if successful, or NULL if we either can't read from
 * the socket or we read something that we can't handle.
 */
char *tds_get_generic_query(TDSSOCKET * tds)
{
 	int token, byte;
	int len, more, i, j;

	for (;;) {
		/*
		 * Read a new packet.  We must explicitly read it,
		 * instead of letting functions such as tds_get_byte()
		 * to read it for us, so that we can examine the packet
		 * type via tds->in_flag.
		 */
		if (tds_read_packet(tds) < 0) {
			return NULL;
		}

		/* Queries can arrive in a couple different formats. */
		switch (tds->in_flag) {
		case TDS_RPC:
			/* TODO */
		case TDS_NORMAL: /* TDS5 query packet */
			/* get the token */
			token = tds_get_byte(tds);
			switch (token) {
			case TDS_LANGUAGE_TOKEN:
				/* SQL query */
				len = tds_get_int(tds); /* query size +1 */
				assert(len >= 1);	/* TODO handle */
				tds_get_byte(tds);	/* has args, ignored TODO */
				if (len > query_buflen) {
					query_buflen = len;
					query = (char *) realloc(query, query_buflen);
				}
				--len;
				tds_get_n(tds, query, len);
				query[len] = 0;
				return query;

			case TDS_DBRPC_TOKEN:
				/* RPC call -- make it look like a query */

				/* skip the overall length */
				(void)tds_get_smallint(tds);

				/* get the length of the stored procedure's name */
				len = tds_get_byte(tds) + 1;/* sproc name size +1 */
				if (len > query_buflen) {
					query_buflen = len;
					query = (char *) realloc(query, query_buflen);
				}

				/*
				 * Read the chars of the name.  Skip NUL
				 * bytes, as a cheap way to convert
				 * Unicode to ASCII.  (For TDS7+, the
				 * name is sent in Unicode.)
				 */
				for (i = j  = 0; i < len - 1; i++) {
					byte = tds_get_byte(tds);
					if (byte != '\0')
						query[j++] = byte;
				}
				query[j] = '\0';

				/* TODO: WE DON'T HANDLE PARAMETERS YET! */

				/* eat the rest of the packet */
				while (!tds_lastpacket(tds) && tds_read_packet(tds) > 0) {
				}
				return query;

			default:
				/* unexpected token */

				/* eat the rest of the packet */
				while (!tds_lastpacket(tds) && tds_read_packet(tds) > 0) {
				}
				return NULL;
			}
			break;

		case TDS_QUERY:
			/* TDS4 and TDS7+ fill the whole packet with a query */
			len = 0;
			for (;;) {
				const char *src;

				/* If buffer needs to grow, then grow */
				more = tds->in_len - tds->in_pos;
				src = (char *) (tds->in_buf + tds->in_pos);
				if ((size_t)(len + more + 1) > query_buflen)
				{
					query_buflen = len + more + 1024u;
					query_buflen -= query_buflen % 1024u;
					query = (char *)realloc(query, query_buflen);
				}

				/*
				 * Pull new data into the query buffer.
				 * Ignore NUL bytes -- this is a cheap way
				 * to convert Unicode to Latin-1/ASCII.
				 */
				while (--more >= 0)
				{
					query[len] = *src++;
					if (query[len] != '\0')
						len++;
				}

				/* if more then read it */
				if (tds_lastpacket(tds))
					break;
				if (tds_read_packet(tds) < 0)
					return NULL;
			}

			/* add a NUL to mark the end */
			query[len] = '\0';
			return query;

		case TDS_CANCEL:
			/*
			 * ignore cancel requests -- if we're waiting
			 * for the next query then it's obviously too
			 * late to cancel the previous query.
			 */
			/* TODO it's not too late -- freddy77 */
			break;

		default:
			/* not a query packet */
			return NULL;
		}
	}
}