int tango_test_connection(tango_connection_t *connection) { if(connection->session_status <= kTangoSessionStatusProtocolNegotiated) { _tango_set_error(connection, kTangoErrorGeneralSystemError, "Not connected yet."); error("tango_test_connection(): No tango_connect() has been successfully called yet."); return -1; } return _tango_ECHO(connection, 2, 'F'); }
int tango_connect(tango_connection_t *connection) { // Connect int result = connect(connection->socket, (struct sockaddr *)&connection->sock_addr, sizeof(struct sockaddr_in)); if(result < 0) { _tango_set_error(connection, kTangoErrorConnectionProblem, "Failed to connect"); error("tango_connect(): Failed to connect(); %s.\n", strerror( errno )); return -1; } if (_tango_NEGOTIATE_PROTOCOL(connection) < 0) return 0; if (_tango_SESSION_SETUP(connection) < 0) return 0; if (_tango_TREE_CONNECT(connection) < 0) return 0; return 1; }
tango_connection_t *tango_create(const char *share, const char* username, const char *password) { static unsigned short next_mid = 0; tango_connection_t *tango_connection_ptr = malloc(sizeof(tango_connection_t)); if (tango_connection_ptr == NULL) { _tango_set_error(tango_connection_ptr, kTangoErrorGeneralSystemError, "tango_create(): Unable to malloc mem.\n"); error("tango_create(): Unable to malloc mem.\n"); return NULL; } // Null it memset(tango_connection_ptr, 0, sizeof(tango_connection_t)); // Create a socket int sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock < 0) { _tango_set_error(tango_connection_ptr, kTangoErrorGeneralSystemError, "tango_create(): Failed to create socket().\n"); debug("tango_create(): Failed to create socket().\n"); goto bailout; } tango_connection_ptr->socket = sock; struct sockaddr_in sock_addr; // Parse share-string if (strncmp(share, "\\\\", 2) != 0 || strlen(share) < 3) { _tango_set_error(tango_connection_ptr, kTangoErrorParameterInvalid, "tango_create(): Passed parameter not a valid share.\n"); debug("tango_create(): Passed parameter not a valid share.\n"); goto bailout; } const char *begin_ptr = share + 2; char *end_ptr = strchr(begin_ptr, '\\'); // Form: \\hostname\share char hostname[64]; assert(strlen(begin_ptr) < 64 && "Hostname longer than 64 bytes"); strncpy(hostname, begin_ptr, end_ptr - begin_ptr); hostname[end_ptr - begin_ptr] = '\0'; sock_addr.sin_addr = address_for_host(hostname); int sin_addr_set = sock_addr.sin_addr.s_addr != INADDR_NONE; if (!sin_addr_set) { _tango_set_error(tango_connection_ptr, kTangoErrorParameterInvalid, "tango_create(): Invalid share.\n"); error("tango_create(): Passed parameter not a valid share or contains no valid hostname/IP.\n"); goto bailout; } char *slash_ptr = strchr(share + 2, '\\'); slash_ptr = strchr(slash_ptr + 1, '\\'); if (slash_ptr != NULL) { // Format: \\hostname\share\subfolder unsigned int slash_idx = slash_ptr - share; strncpy(tango_connection_ptr->share, share, slash_idx); tango_connection_ptr->share[slash_idx + 1] = '\0'; } else { // Format: \\hostname\share slash_ptr = strchr(share + 2, '\\'); strcpy(tango_connection_ptr->share, slash_ptr+1); } // Configure port and connection-type sock_addr.sin_family = AF_INET; sock_addr.sin_port = htons(445); // Default-port for SMB over TCP/IP without NetBios tango_connection_ptr->sock_addr = sock_addr; // Set our Ids tango_connection_ptr->pid = 0x1234; tango_connection_ptr->mid = next_mid++; // Store username and password strcpy(tango_connection_ptr->user_name, username); strcpy(tango_connection_ptr->user_password, password); return tango_connection_ptr; bailout: free(tango_connection_ptr); return NULL; }
int _tango_TREE_CONNECT(tango_connection_t *connection) { unsigned int operation_successful = -1; /** * 1. Define Request */ tango_smb_t *smb = _tango_create_smb(); // Header _tango_populate_request_header(connection, smb, SMB_COM_TREE_CONNECT_ANDX); // Parameters unsigned char *parameters_ptr = _tango_smb_getParametersPointer(smb); unsigned int parameters_offset = 0; // AndX Command *((unsigned char *)(parameters_ptr + parameters_offset)) = SMB_COM_NONE; parameters_offset+=2; // 1 byte reserved // AndX Offset *((unsigned short *)(parameters_ptr + parameters_offset)) = 0; parameters_offset+=2; // Flags *((unsigned short *)(parameters_ptr + parameters_offset)) = 0x00; parameters_offset+=2; // PasswordLength; *((unsigned short *)(parameters_ptr + parameters_offset)) = 1; parameters_offset+=2; _tango_smb_setParametersSize(smb, parameters_offset); // Data unsigned char *data_ptr = _tango_smb_getDataPointer(smb); unsigned int data_offset = 0; //msg_data.byte_count = 1 + strlen(connection->share) + 1 + 6; // Password strcpy((char *)(data_ptr + data_offset), ""); data_offset += strlen((char *)(data_ptr + data_offset)) + 1; // Path strcpy((char *)(data_ptr + data_offset), connection->share); data_offset += strlen((char *)(data_ptr + data_offset)) + 1; // Service strcpy((char *)(data_ptr + data_offset), "?????"); data_offset += strlen((char *)(data_ptr + data_offset)) + 1; _tango_smb_setDataSize(smb, data_offset); /** * 2. Send Request and receive Response */ #ifdef VERY_VERBOSE printf("_tango_TREE_CONNECT_ANDX(): Sending TREE_CONNECT_ANDX:\n"); printf("-----------------------------------------------------------------------------\n"); _tango_print_message(smb); printf("-----------------------------------------------------------------------------\n"); #endif if (!_tango_send_and_receive(connection, smb, NULL)) { goto bailout; } debug("_tango_TREE_CONNECT_ANDX(): Received response\n"); /** * 3. Evaluate Response */ if (!_tango_evaluate_response_header(connection, smb)) { goto bailout; } if (_tango_smb_getParametersSize(smb) != 6) { _tango_set_error(connection, kTangoErrorInvalidResponseMessage, "Unable to connect to share"); error("_tango_TREE_CONNECT_ANDX(): Parameters-block length %d (!= 6).\n", (int)_tango_smb_getParametersSize(smb)); goto bailout; } #ifdef VERY_VERBOSE printf("_tango_TREE_CONNECT_ANDX(): Received response:\n"); printf("-----------------------------------------------------------------------------\n"); _tango_print_message(smb); printf("-----------------------------------------------------------------------------\n"); #endif connection->session_status = kTangoSessionStatusConnectedToShare; operation_successful = 1; bailout: _tango_release_smb(smb); return operation_successful; }
int _tango_NEGOTIATE_PROTOCOL(tango_connection_t *connection) { int operation_successful = -1; /** * 1. Define Request */ tango_smb_t *smb = _tango_create_smb(); // Header _tango_populate_request_header(connection, smb, SMB_COM_NEGOTIATE); // Parameters unsigned char *parameters_ptr = _tango_smb_getParametersPointer(smb); _tango_smb_setParametersSize(smb, 0); // Data unsigned char *data_ptr = _tango_smb_getDataPointer(smb); unsigned int data_offset = 0; // Set to LanManager 0.12 for NT data_ptr[0] = 0x02; data_offset++; strcpy((char *)(data_ptr + data_offset), SMB_NEGOTIATE_PROTOCOL_DIALECT_LM012); data_offset += strlen(SMB_NEGOTIATE_PROTOCOL_DIALECT_LM012) + 1; _tango_smb_setDataSize(smb, data_offset); /** * 2. Send Request and receive Response */ #ifdef VERY_VERBOSE printf("_tango_NEGOTIATE_PROTOCOL(): Sending NEGOTIATE_PROTOCOL request:\n"); printf("-----------------------------------------------------------------------------\n"); _tango_print_message(smb); printf("-----------------------------------------------------------------------------\n"); #endif if (!_tango_send_and_receive(connection, smb, NULL)) { goto bailout; } debug("_tango_NEGOTIATE_PROTOCOL(): Received response\n"); /** * 3. Evaluate Response */ if (!_tango_evaluate_response_header(connection, smb)) { goto bailout; } // Read Parameters if (_tango_smb_getParametersSize(smb) != 34) { _tango_set_error(connection, kTangoErrorInvalidResponseMessage, "Invalid response.\n"); debug("_tango_NEGOTIATE_PROTOCOL(): Parameters-block length %d (!= 34).\n", (int)_tango_smb_getParametersSize(smb)); goto bailout; } /** TODO if no index is supported! Server Response ================ UCHAR WordCount; USHORT DialectIndex; USHORT ByteCount; Description ============ Count of parameter words = 1 Index of selected dialect Count of data bytes = 0 */ #ifdef VERY_VERBOSE printf("_tango_NEGOTIATE_PROTOCOL(): Received response for NEGOTIATE_PROTOCOL_REQUEST:\n"); printf("-----------------------------------------------------------------------------\n"); _tango_print_NEGOTIATE_PROTOCOL_RESPONSE(smb); printf("-----------------------------------------------------------------------------\n"); #endif parameters_ptr = _tango_smb_getParametersPointer(smb); // params->DialectIndex // We assume he is Ok with our dialect as the NT_STATUS Level was set to SUCCESS // params->SecurityMode // TODO: Handle Sec mode // params->MaxMpxCount // Don't care for now // params->MaxNumberVCs // Don't care for now //connection->max_buffer_size = params->MaxBufferSize; // params->MaxRawSize // We don't support raw-mode to keep it easy // params->SessionKey connection->session_key = *(unsigned int *)(parameters_ptr + SMB_NEGOTIATE_PROTOCOL_RSP_PARAMETERS_SESSION_KEY_INT); // params->Capabilities unsigned int capabilities = *(unsigned int *)(parameters_ptr + SMB_NEGOTIATE_PROTOCOL_RSP_PARAMETERS_CAPABILITIES_INT); connection->extended_security = capabilities & CAP_EXTENDED_SECURITY; if (connection->extended_security) { error("_tango_NEGOTIATE_PROTOCOL(): Extended Security unsupported.\n"); _tango_set_error(connection, kTangoErrorUnsupported, "Unsupported security mode"); goto bailout; } debug("_tango_NEGOTIATE_PROTOCOL(): Server Capabilities 0x%x\n", capabilities); connection->server_capabilities = capabilities; if (capabilities & CAP_LARGE_READX) { debug("_tango_NEGOTIATE_PROTOCOL(): - CAP_LARGE_READX\n"); } //time_t time = (time_t)((((((unsigned long)params->SystemTimeLow) << 32) | params->SystemTimeHigh)/10000000) - 11644473600); // params->ServerTimeZone // Too late... don't care for it now // params->EncryptionKeyLength unsigned char encryption_key_length = *(unsigned char *)(parameters_ptr + SMB_NEGOTIATE_PROTOCOL_RSP_PARAMETERS_ENCRYPTION_KEY_LENGTH_BYTE); // Store challange (no extended security) if (encryption_key_length == 0) { debug("_tango_NEGOTIATE_PROTOCOL(): No encryption (key-length == 0)\n"); } else if (encryption_key_length == 8) { // Ok } else { error("_tango_NEGOTIATE_PROTOCOL(): Unsupported key-length (key-length = %u)\n", encryption_key_length); _tango_set_error(connection, kTangoErrorUnsupported, "Unsupported encryption.\n"); } // Read Data data_ptr = _tango_smb_getDataPointer(smb); if (encryption_key_length == 8) { memcpy(&connection->sec_challenge, data_ptr, 8); } operation_successful = 1; connection->session_status = kTangoSessionStatusProtocolNegotiated; bailout: _tango_release_smb(smb); return operation_successful; }
int _tango_ECHO(tango_connection_t *connection, unsigned short number_of_echoes, char echoPayload) { unsigned int operation_successful = -1; /** * 1. Define Request */ tango_smb_t *smb = _tango_create_smb(); _tango_populate_request_header(connection, smb, SMB_COM_ECHO); // Parameters unsigned char *parameters_ptr = _tango_smb_getParametersPointer(smb); unsigned int parameters_offset = 0; // Echo count *((unsigned short *)(parameters_ptr + parameters_offset)) = number_of_echoes; parameters_offset+=2; _tango_smb_setParametersSize(smb, parameters_offset); // Data unsigned char *data_ptr = _tango_smb_getDataPointer(smb); unsigned int data_offset = 0; *((unsigned char *)(data_ptr + data_offset)) = echoPayload; data_offset+=1; _tango_smb_setDataSize(smb, data_offset); /** * 2. Send Request and receive Response */ #ifdef VERY_VERBOSE printf("_tango_ECHO(): Sending ECHO:\n"); printf("-----------------------------------------------------------------------------\n"); _tango_print_message(smb); printf("-----------------------------------------------------------------------------\n"); #endif if (!_tango_send(connection, smb)) { goto bailout; } for (int i=1; i<=number_of_echoes; i++) { if (!_tango_receive(connection, smb)) { goto bailout; } debug("_tango_ECHO(): Received response %d of %d\n", i, number_of_echoes); /** * 3. Evaluate Response */ if (!_tango_evaluate_response_header(connection, smb)) { goto bailout; } if (_tango_smb_getParametersSize(smb) != 2) { _tango_set_error(connection, kTangoErrorInvalidResponseMessage, "Operation failed"); error("_tango_ECHO(): Parameters-block length %d (!= 2).\n", (int)_tango_smb_getParametersSize(smb)); goto bailout; } #ifdef VERY_VERBOSE printf("_tango_ECHO(): Received response:\n"); printf("-----------------------------------------------------------------------------\n"); _tango_print_message(smb); printf("-----------------------------------------------------------------------------\n"); #endif data_ptr = _tango_smb_getDataPointer(smb); data_offset = 0; char echo = *((unsigned char *)(data_ptr + data_offset)); if (echoPayload != echo) { _tango_set_error(connection, kTangoErrorInvalidResponseMessage, "Invalid response"); error("_tango_ECHO(): Echo does not echo (%02x) the payload of request (%02x).\n", echo, echoPayload); goto bailout; } } operation_successful = 1; bailout: _tango_release_smb(smb); return operation_successful; }