/** * 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); }
int set_and_get_mysql_users_wildcards(char *username, char *hostname, char *password, char *from, char *anydb, char *db, char *db_from) { USERS *mysql_users; int ret = -1; struct sockaddr_in client_addr; DCB *dcb; SERVICE *service; MYSQL_session *data; dcb = dcb_alloc(DCB_ROLE_INTERNAL); if (dcb == NULL) { fprintf(stderr, "dcb_alloc() failed\n"); return ret; } if ((service = (SERVICE *)calloc(1, sizeof(SERVICE))) == NULL) { fprintf(stderr, "service_alloc() failed\n"); dcb_free(dcb); return ret; } memset(&client_addr, 0, sizeof(client_addr)); if (hostname) { if(!setipaddress(&client_addr.sin_addr, from)) { fprintf(stderr, "setipaddress failed for host [%s]\n", from); free(service); dcb_free(dcb); return ret; } } if ((data = (MYSQL_session *) calloc(1, sizeof(MYSQL_session))) == NULL) { fprintf(stderr, "MYSQL_session alloc failed\n"); free(service); dcb_free(dcb); return ret; } /* client IPv4 in raw data*/ memcpy(&dcb->ipv4, (struct sockaddr_in *)&client_addr, sizeof(struct sockaddr_in)); dcb->service = service; mysql_users = mysql_users_alloc(); service->users = mysql_users; if (db_from != NULL) strncpy(data->db, db_from,MYSQL_DATABASE_MAXLEN); else strncpy(data->db, "",MYSQL_DATABASE_MAXLEN); /* freed by dcb_free(dcb) */ dcb->data = data; // the routine returns 1 on success if (anydb != NULL) { if (strcmp(anydb, "N") == 0) { ret = add_mysql_users_with_host_ipv4(mysql_users, username, hostname, password, anydb, db); } else if (strcmp(anydb, "Y") == 0) { ret = add_mysql_users_with_host_ipv4(mysql_users, username, hostname, password, "Y", ""); } else { ret = add_mysql_users_with_host_ipv4(mysql_users, username, hostname, password, "N", NULL); } } else { ret = add_mysql_users_with_host_ipv4(mysql_users, username, hostname, password, "N", NULL); } if (ret == 0) { fprintf(stderr, "add_mysql_users_with_host_ipv4 (%s@%s, %s) FAILED\n", username, hostname, password); } else { unsigned char db_passwd[100]=""; dcb->remote=strdup(from); // returns 0 on success ret = gw_find_mysql_user_password_sha1(username, db_passwd, dcb); } users_free(mysql_users); free(service); dcb_free(dcb); return ret; }