?? newcamd-client.cpp
字號:
// implements the newcamd protocol (versions 5.20 & 5.25)
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/poll.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include "newcamd-client.h"
#define COMPILE_DATE 20080802
unsigned short int _htons(unsigned short int hostshort)
{
unsigned short int netshort;
((unsigned char *)(&netshort))[0] = (hostshort >> 8) & 0xFF;
((unsigned char *)(&netshort))[1] = (hostshort >> 0) & 0xFF;
return netshort;
}
// ------------------------------- newcamd client class member implementation ------------------------------
newcamd_client::newcamd_client(char *server_url, unsigned int timeout, protocol_version_t version)
{
set_protocol_version( version );
status = 0;
status_description[0] = 0;
ready = false;
network_timeout = timeout;
sent_sequence_id = 0;
received_sequence_id = 0;
memset(cw_0, 0, sizeof(cw_0));
memset(cw_1, 0, sizeof(cw_1));
strcpy(url, server_url);
memset(username, 0, sizeof(username));
memset(password, 0, sizeof(password));
memset(hostname, 0, sizeof(hostname));
port = 0;
user_id = -1;
card_caid = 0;
card_provider_id_count = 0;
memset(cam_id, 0, sizeof(cam_id));
memset(random_key, 0, sizeof(random_key));
memset(des_key, 0, sizeof(des_key));
memset(login_key, 0, sizeof(login_key));
memset(session_key, 0, sizeof(session_key));
memset(expanded_login_key, 0, sizeof(expanded_login_key));
memset(expanded_session_key, 0, sizeof(expanded_session_key));
parse_url();
server_connect();
if( status ) return;
server_login();
ready = true;
dbg = 0;
}
bool newcamd_client::is_ready( void )
{
return ready;
}
void newcamd_client::set_protocol_version( protocol_version_t version )
{
protocol_version = version;
switch( version )
{
case VERSION_520:
custom_data_length = 4;
break;
case VERSION_525:
custom_data_length = 8;
break;
default:
custom_data_length = 8;
break;
}
set_sid( 0x0666 ); //rqcamd client id
}
void newcamd_client::set_sid( unsigned short int sid )
{
memset(custom_data, 0, sizeof(custom_data));
switch( protocol_version )
{
case VERSION_520:
custom_data[2] = sid >> 8;
custom_data[3] = sid & 0xFF;
break;
case VERSION_525:
custom_data[0] = sid >> 8;
custom_data[1] = sid & 0xFF;
break;
default:
custom_data[0] = sid >> 8;
custom_data[1] = sid & 0xFF;
break;
}
}
void newcamd_client::parse_url( void )
{
char config_key[29];
char emm_config[4];
unsigned char config_key_byte_count = sizeof(des_key);
int des_key_byte;
memset(config_key, 0, sizeof(config_key));
sscanf(url, "newcamd://%[^:]:%[^@]@%[^:]:%d/%28s/%3s", username, password, hostname, &port, config_key, emm_config);
while( config_key_byte_count-- )
{
sscanf(&config_key[config_key_byte_count * 2], "%02X", &des_key_byte);
des_key[config_key_byte_count] = (unsigned char)des_key_byte;
}
des_key[config_key_byte_count] = 0;
if( !strcmp(emm_config, "EMM") )
process_emms = true;
else
process_emms = false;
}
newcamd_client::~newcamd_client( void )
{
server_disconnect();
}
void newcamd_client::server_connect( void )
{
struct hostent *host_address;
struct sockaddr_in socket_address;
host_address = gethostbyname(hostname);
if(!host_address)
{
status = 1;
printf("[Newcamd] Could not resolve hostname.\n");
return;
}
if((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
status = 1;
printf("[Newcamd] Could not get socket descriptor.\n");
return;
}
socket_address.sin_family = AF_INET;
socket_address.sin_port = _htons(port);
socket_address.sin_addr.s_addr = ((struct in_addr *) host_address->h_addr)->s_addr;
if( connect(fd, (struct sockaddr *)(&socket_address), sizeof(struct sockaddr)) < 0 )
{
status = 1;
printf("[Newcamd] Failed to connect to remote server.\n");
return;
}
status = 0;
printf("[Newcamd] Successfully connected to server.\n");
}
void newcamd_client::server_disconnect( void )
{
shutdown(fd, 2);
close(fd);
}
void newcamd_client::server_login( void )
{
unsigned char buffer[CWS_NETMSGSIZE];
memset(buffer, 0, CWS_NETMSGSIZE);
// ----------------------------------------- LOGIN --------------------------------------------------
//server should initiate sequence with 14-byte random key. get it and create the login key
if( network_read(random_key, sizeof(random_key)) != sizeof(random_key) )
{
status = 1;
printf( "[Newcamd] Failed to receive random server key.");
return;
}
create_login_key(); //xor random key with common des key
//build login command data
char *encrypted_password = crypt(password,"$1$abcdefgh$");
unsigned short int username_length = strlen(username);
unsigned short int password_length = strlen(encrypted_password);
memcpy(buffer, username, username_length + 1);
memcpy(buffer + username_length + 1, encrypted_password, password_length + 1);
//send login command, if error, exit.
send_command(MSG_CLIENT_2_SERVER_LOGIN, buffer, username_length + 1 + password_length + 1, custom_data, LOGIN_KEY);
if( status ) return;
//command sent successfully, get server response, if error, exit.
int command = receive_command( NULL, LOGIN_KEY );
if( status ) return;
//server response received succesfully, check if login is acknowledged, if not, exit.
if( command != MSG_CLIENT_2_SERVER_LOGIN_ACK )
{
status = 1;
printf("[Newcamd] Login request was rejected.\n");
return;
}
// --------------------------------------- CARD DATA REQUEST -------------------------------------
//login was successful, now create session key
create_session_key( encrypted_password ); //xor password with common des key
//from now on, all messages are encrypted with the session key
//request card data
send_command(MSG_CARD_DATA_REQ, 0, 0, custom_data, SESSION_KEY);
if( status ) return;
//command sent successfully, get server response, if error, exit.
receive_message(buffer, NULL, SESSION_KEY );
if( status ) return;
//server response received succesfully, check if login is acknowledged, if not, exit.
if( buffer[0] != MSG_CARD_DATA )
{
status = 1;
printf( "[Newcamd] Card data request failed.\n");
return;
}
//parse card data
card_caid = buffer[4] << 8 | buffer[5]; //get caid. it is stored at bytes 4 & 5 (big-endian)
user_id = buffer[3]; //get user id assigned by server.
//check if cam id was provided.
if( memcmp(buffer + 6, "\0\0\0\0\0\0\0\0", 8) )
{
//cam id info is present, get the data according to caid
switch( card_caid >> 8 )
{
case 0x18: //nagra
memcpy(cam_id, buffer + 6 + 4, 4);
break;
}
}
card_provider_id_count = buffer[14] > MAX_CARD_PROVIDER_COUNT ? MAX_CARD_PROVIDER_COUNT : buffer[14];
//fill provider id's collection
for(int i=0;i<card_provider_id_count;i++)
card_provider_id[i] = (buffer[15 + (i * 11) + 1] << 8) | buffer[15 + (i * 11) + 2];
}
void newcamd_client::send_ecm(unsigned char *ecm_data, unsigned short int ecm_data_length, unsigned short int sid)
{
unsigned char buffer[CWS_NETMSGSIZE];
int bytes_received, i;
//set the sid in custom data field
set_sid( sid );
//send the ecm, exit if error status
send_message(ecm_data, ecm_data_length, custom_data, SESSION_KEY);
if( status ) return;
//this receive loop is to discard any old messages left in the socket read buffer due
//to fast service switching (without this, fast service switching does not work properly).
while( 1 )
{
bytes_received = receive_message(buffer, 0, SESSION_KEY);
if( status ) return;
if( received_sequence_id == sent_sequence_id ) break;
if( received_sequence_id > sent_sequence_id )
{
status = 1;
printf("[Newcamd] Future sequence id received. ECM request failed.\n");
return;
}
/*
if( received_sequence_id < sent_sequence_id )
printf("seq id mismatch! sent: %d, recv: %d", sent_sequence_id, received_sequence_id);
*/
}
switch( bytes_received )
{
case 3 + 16: //19 bytes where received (3-byte header + 16-byte control words)
//copy control words
if( memcmp(buffer + 3 + 0, "\0\0\0\0", 4) ) memcpy(cw_0, buffer + 3 + 0, sizeof(cw_0));
if( memcmp(buffer + 3 + 8, "\0\0\0\0", 4) ) memcpy(cw_1, buffer + 3 + 8, sizeof(cw_1));
status = 0;
if (dbg)
{
printf( "[Newcamd] Control words received successfully.\n");
for (i=0;i<19;i++) printf("%02x ",buffer[i]); printf("\n");
}
break;
case 3: //only header received, no control words
status = 1;
printf( "[Newcamd] Control words not received.\n");
break;
default:
status = 2;
printf( "[Newcamd] Invalid server response (%d bytes received).\n", bytes_received);
break;
break;
}
}
void newcamd_client::send_emm(unsigned char *emm_data, unsigned short int emm_data_length)
{
unsigned char buffer[CWS_NETMSGSIZE];
unsigned int bytes_received;
if( process_emms /* && memcmp(cam_id, "\0\0\0\0", 4) */ )
{
send_message(emm_data, emm_data_length, 0, SESSION_KEY);
if( status ) return;
//this receive loop is to discard any old messages left in the socket read buffer due
//to fast service switching (without this, fast service switching does not work properly).
while( 1 )
{
bytes_received = receive_message(buffer, 0, SESSION_KEY);
if( status ) return;
if( received_sequence_id > sent_sequence_id )
{
status = 1;
printf( "[Newcamd] Future sequence id received. EMM request failed.\n");
return;
}
if( received_sequence_id == sent_sequence_id ) break;
}
if( bytes_received < 3 )
{
status = 1;
printf( "[Newcamd] Invalid server response while processing EMM.\n");
}
else
{
if( buffer[1] & 0x10 )
{
status = 0;
printf( "[Newcamd] EMM processed correctly by card.\n");
}
else
{
status = 1;
printf( "[Newcamd] EMM rejected by card.\n");
}
}
}
else
{
status = 1;
printf( "[Newcamd] EMM processing has been disabled.\n");
}
}
void newcamd_client::send_command(net_msg_type_t command, unsigned char *data, unsigned short int data_length, unsigned char *custom_data, key_encryption_t key_type)
{
unsigned char command_buffer[3 + data_length];
command_buffer[0] = command;
command_buffer[1] = (data_length >> 8) & 0x0F;
command_buffer[2] = data_length & 0xFF;
if( data ) memcpy(command_buffer + 3, data, data_length);
return send_message(command_buffer, sizeof(command_buffer), custom_data, key_type);
}
net_msg_type_t newcamd_client::receive_command( unsigned char *custom_data, key_encryption_t key_type )
{
unsigned char command_buffer[CWS_NETMSGSIZE];
if( receive_message(command_buffer, custom_data, key_type) == 3 )
return (net_msg_type_t) command_buffer[0];
else
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -