Ejemplo n.º 1
0
/**
 * Encrypt a password that can be stored in the MaxScale configuration file.
 *
 * Note the return is always a malloc'd string that the caller must free
 *
 * @param password	The password to encrypt
 * @return	The encrypted password
 */
char *
encryptPassword(char *password)
{
MAXKEYS		*keys;
AES_KEY		aeskey;
int		padded_len;
char		*hex_output;
unsigned char	padded_passwd[80];
unsigned char	encrypted[80];

	if ((keys = secrets_readKeys()) == NULL)
		return NULL;

	memset(padded_passwd, 0, 80);
	strcpy((char *)padded_passwd, password);
	padded_len = ((strlen(password) / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE;

	AES_set_encrypt_key(keys->enckey, 8 * MAXSCALE_KEYLEN, &aeskey);

	AES_cbc_encrypt(padded_passwd, encrypted, padded_len, &aeskey, keys->initvector, AES_ENCRYPT);
	hex_output = (char *)malloc(padded_len * 2);
	gw_bin2hex(hex_output, encrypted, padded_len);
	free(keys);

	return	hex_output;
}
Ejemplo n.º 2
0
/**
 * Create a HEX(SHA1(SHA1(password)))
 *
 * @param password	The password to encrypt
 * @return		The new allocated encrypted password, that the caller must free
 *
 */
char *create_hex_sha1_sha1_passwd(char *passwd) {
	uint8_t hash1[SHA_DIGEST_LENGTH]="";
	uint8_t hash2[SHA_DIGEST_LENGTH]="";
	char *hexpasswd=NULL;
	
	if ((hexpasswd = (char *)calloc(SHA_DIGEST_LENGTH * 2 + 1, 1)) == NULL)
		return NULL;

	/* hash1 is SHA1(real_password) */
	gw_sha1_str((uint8_t *)passwd, strlen(passwd), hash1);

	/* hash2 is the SHA1(input data), where input_data = SHA1(real_password) */
	gw_sha1_str(hash1, SHA_DIGEST_LENGTH, hash2);

	/* dbpass is the HEX form of SHA1(SHA1(real_password)) */
	gw_bin2hex(hexpasswd, hash2, SHA_DIGEST_LENGTH);

	return hexpasswd;
}
Ejemplo n.º 3
0
/**
 * gw_check_mysql_scramble_data
 *
 * Check authentication token received against stage1_hash and scramble
 *
 * @param dcb The current dcb
 * @param token 	The token sent by the client in the authentication request
 * @param token_len 	The token size in bytes
 * @param scramble 	The scramble data sent by the server during handshake
 * @param scramble_len 	The scrable size in bytes
 * @param username	The current username in the authentication request
 * @param stage1_hash	The SHA1(candidate_password) decoded by this routine
 * @return 0 on succesful check or != 0 on failure
 *
 */
int gw_check_mysql_scramble_data(DCB *dcb, uint8_t *token, unsigned int token_len, uint8_t *scramble, unsigned int scramble_len, char *username, uint8_t *stage1_hash) {
	uint8_t step1[GW_MYSQL_SCRAMBLE_SIZE]="";
	uint8_t step2[GW_MYSQL_SCRAMBLE_SIZE +1]="";
	uint8_t check_hash[GW_MYSQL_SCRAMBLE_SIZE]="";
	char hex_double_sha1[2 * GW_MYSQL_SCRAMBLE_SIZE + 1]="";
	uint8_t password[GW_MYSQL_SCRAMBLE_SIZE]="";
	int ret_val = 1;

	if ((username == NULL) || (scramble == NULL) || (stage1_hash == NULL)) {
		return 1;
	}

	/*<
	 * get the user's password from repository in SHA1(SHA1(real_password));
	 * please note 'real_password' is unknown!
	 */

	ret_val = gw_find_mysql_user_password_sha1(username, password, dcb);

	if (ret_val) {
		return 1;
	}

	if (token && token_len) {
		/*<
		 * convert in hex format: this is the content of mysql.user table.
		 * The field password is without the '*' prefix and it is 40 bytes long
		 */

		gw_bin2hex(hex_double_sha1, password, SHA_DIGEST_LENGTH);
	} else {
		/* check if the password is not set in the user table */
		if (!strlen((char *)password)) {
			/* Username without password */
			return 0;
		} else {
			return 1;
		}
	}

	/*<
	 * Auth check in 3 steps
	 *
	 * Note: token = XOR (SHA1(real_password), SHA1(CONCAT(scramble, SHA1(SHA1(real_password)))))
	 * the client sends token
	 *
	 * Now, server side:
	 *
	 *
	 * step 1: compute the STEP1 = SHA1(CONCAT(scramble, gateway_password))
	 * the result in step1 is SHA_DIGEST_LENGTH long
	 */

	gw_sha1_2_str(scramble, scramble_len, password, SHA_DIGEST_LENGTH, step1);

	/*<
	 * step2: STEP2 = XOR(token, STEP1)
	 *
	 * token is trasmitted form client and it's based on the handshake scramble and SHA1(real_passowrd)
	 * step1 has been computed in the previous step
	 * the result STEP2 is SHA1(the_password_to_check) and is SHA_DIGEST_LENGTH long
	 */

	gw_str_xor(step2, token, step1, token_len);

	/*<
	 * copy the stage1_hash back to the caller
	 * stage1_hash will be used for backend authentication
	 */
	
	memcpy(stage1_hash, step2, SHA_DIGEST_LENGTH);

	/*<
	 * step 3: prepare the check_hash
	 *	
	 * compute the SHA1(STEP2) that is SHA1(SHA1(the_password_to_check)), and is SHA_DIGEST_LENGTH long
	 */
	
	gw_sha1_str(step2, SHA_DIGEST_LENGTH, check_hash);


#ifdef GW_DEBUG_CLIENT_AUTH
	{
		char inpass[128]="";
		gw_bin2hex(inpass, check_hash, SHA_DIGEST_LENGTH);
		
		fprintf(stderr, "The CLIENT hex(SHA1(SHA1(password))) for \"%s\" is [%s]", username, inpass);
	}
#endif

	/* now compare SHA1(SHA1(gateway_password)) and check_hash: return 0 is MYSQL_AUTH_OK */
	return memcmp(password, check_hash, SHA_DIGEST_LENGTH);
}
Ejemplo n.º 4
0
/**
 * Write a MySQL CHANGE_USER packet to backend server
 *
 * @param conn  MySQL protocol structure
 * @param dbname The selected database
 * @param user The selected user
 * @param passwd The SHA1(real_password): Note real_password is unknown
 * @return 1 on success, 0 on failure
 */
int gw_send_change_user_to_backend(char *dbname, char *user, uint8_t *passwd, MySQLProtocol *conn) {
        int compress = 0;
        int rv;
        uint8_t *payload = NULL;
        uint8_t *payload_start = NULL;
        long bytes;
        uint8_t client_scramble[GW_MYSQL_SCRAMBLE_SIZE];
        uint8_t client_capabilities[4];
        uint32_t server_capabilities;
        uint32_t final_capabilities;
        char dbpass[MYSQL_USER_MAXLEN + 1]="";
	GWBUF *buffer;
	DCB *dcb;

        char *curr_db = NULL;
        uint8_t *curr_passwd = NULL;

        if (strlen(dbname))
                curr_db = dbname;

        if (strlen((char *)passwd))
                curr_passwd = passwd;

	dcb = conn->owner_dcb;

	// Zero the vars
	memset(&server_capabilities, '\0', sizeof(server_capabilities));
	memset(&final_capabilities, '\0', sizeof(final_capabilities));

        final_capabilities = gw_mysql_get_byte4((uint8_t *)&server_capabilities);

        final_capabilities |= GW_MYSQL_CAPABILITIES_PROTOCOL_41;
        final_capabilities |= GW_MYSQL_CAPABILITIES_CLIENT;

        if (compress) {
                final_capabilities |= GW_MYSQL_CAPABILITIES_COMPRESS;
#ifdef DEBUG_MYSQL_CONN
                fprintf(stderr, ">>>> Backend Connection with compression\n");
#endif
        }

        if (curr_passwd != NULL) {
                uint8_t hash1[GW_MYSQL_SCRAMBLE_SIZE]="";
                uint8_t hash2[GW_MYSQL_SCRAMBLE_SIZE]="";
                uint8_t new_sha[GW_MYSQL_SCRAMBLE_SIZE]="";

		// hash1 is the function input, SHA1(real_password)
                memcpy(hash1, passwd, GW_MYSQL_SCRAMBLE_SIZE);

		// hash2 is the SHA1(input data), where input_data = SHA1(real_password)
                gw_sha1_str(hash1, GW_MYSQL_SCRAMBLE_SIZE, hash2);

		// dbpass is the HEX form of SHA1(SHA1(real_password))
                gw_bin2hex(dbpass, hash2, GW_MYSQL_SCRAMBLE_SIZE);

		// new_sha is the SHA1(CONCAT(scramble, hash2)
                gw_sha1_2_str(conn->scramble, GW_MYSQL_SCRAMBLE_SIZE, hash2, GW_MYSQL_SCRAMBLE_SIZE, new_sha);

		// compute the xor in client_scramble
                gw_str_xor(client_scramble, new_sha, hash1, GW_MYSQL_SCRAMBLE_SIZE);

        }

        if (curr_db == NULL) {
                // without db
                final_capabilities &= ~GW_MYSQL_CAPABILITIES_CONNECT_WITH_DB;
        } else {
                final_capabilities |= GW_MYSQL_CAPABILITIES_CONNECT_WITH_DB;
        }

        final_capabilities |= GW_MYSQL_CAPABILITIES_PLUGIN_AUTH;

        gw_mysql_set_byte4(client_capabilities, final_capabilities);

	// Protocol MySQL COM_CHANGE_USER for CLIENT_PROTOCOL_41
	// 1 byte COMMAND
        bytes = 1;

	// add the user
        bytes += strlen(user);
        // the NULL
        bytes++;

	// next will be + 1 (scramble_len) + 20 (fixed_scramble) + (dbname + NULL term) + 2 bytes charset 

        if (curr_passwd != NULL) {
                bytes += GW_MYSQL_SCRAMBLE_SIZE;
                bytes++;
	} else {
                bytes++;
	}	

        if (curr_db != NULL) {
                bytes += strlen(curr_db);
        	bytes++;
	}

	// the charset
	bytes += 2;
        bytes += strlen("mysql_native_password");
        bytes++;

        // the packet header
        bytes += 4;

	// allocating the GWBUF
	buffer = gwbuf_alloc(bytes);
	payload = GWBUF_DATA(buffer);

	// clearing data
	memset(payload, '\0', bytes);
	
	// save the start pointer
	payload_start = payload;

	// set packet # = 1
        payload[3] = 0x00;
        payload += 4;

	// set the command COM_CHANGE_USER \x11
	payload[0] = 0x11;
        payload++;

	memcpy(payload, user, strlen(user));
        payload += strlen(user);
        payload++;

        if (curr_passwd != NULL) {
                // set the auth-length
                *payload = GW_MYSQL_SCRAMBLE_SIZE;
                payload++;

                //copy the 20 bytes scramble data after packet_buffer+36+user+NULL+1 (byte of auth-length)
                memcpy(payload, client_scramble, GW_MYSQL_SCRAMBLE_SIZE);

                payload += GW_MYSQL_SCRAMBLE_SIZE;

        } else {
                // skip the auth-length and write a NULL
                payload++;
        }

        // if the db is not NULL append it
        if (curr_db != NULL) {
                memcpy(payload, curr_db, strlen(curr_db));
                payload += strlen(curr_db);
                payload++;
        }

        // set the charset, 2 bytes!!!!
        *payload = '\x08';
        payload++;
        *payload = '\x00';
        payload++;

        memcpy(payload, "mysql_native_password", strlen("mysql_native_password"));

        payload += strlen("mysql_native_password");
        payload++;

	// put here the paylod size: bytes to write - 4 bytes packet header
        gw_mysql_set_byte3(payload_start, (bytes-4));

	rv = dcb->func.write(dcb, buffer);

	if (rv == 0)
		return 0;
	else
		return 1;
}