./ MultiCS.r82 / cli-newcamd.c
static char string_newcamd[] = "Newcamd";
static char string_mgcamd[] = "Mgcamd";
static char string_newcamd_mcs[] = "Newcamd-MCS";
static char string_mgcamd_mcs[] = "Mgcamd-MCS";
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
int cs_connect_srv(struct server_data *srv, int fd)
{
char passwdcrypt[120];
unsigned char keymod[14];
int i,index,len;
unsigned char buf[CWS_NETMSGSIZE];
unsigned char sessionkey[16];
// INIT
srv->progname = NULL;
memset( srv->version, 0, sizeof(srv->version) );
memset( srv->build, 0, 32);
//
if( recv_nonb(fd, keymod, 14,5000) != 14 ) {
static char msg[]= "Server does not return init sequence";
srv->statmsg = msg;
debugf(getdbgflag(DBG_SERVER,0,srv->id)," newcamd: server does not return init sequence\n");
return -1;
}
// Check Multics
int ismultics = 0;
uint8_t a = (keymod[0]^'M') + keymod[1] + keymod[2];
uint8_t b = keymod[4] + (keymod[5]^'C') + keymod[6];
uint8_t c = keymod[8] + keymod[9] + (keymod[10]^'S');
if ( (a==keymod[3])&&(b==keymod[7])&&(c==keymod[11]) ) {
ismultics = 1;
}
//debugdump(keymod,14,"Recv DES Key: ");
des_login_key_get(keymod, srv->key, 14, sessionkey);
//debugdump(sessionkey,16,"Login Key: ");
// 3. Send login info
struct cs_custom_data clicd; // Custom data
memset( &clicd, 0, sizeof(clicd));
//clicd.sid = 0x4343; // CCcam
clicd.sid = cfg.newcamd.clientid; // Mgcamd
index = 3;
buf[0] = MSG_CLIENT_2_SERVER_LOGIN;
buf[1] = 0;
strcpy( (char*)&buf[3], srv->user);
index += strlen(srv->user)+1;
__md5_crypt(srv->pass, "$1$abcdefgh$",passwdcrypt);
//debugf(getdbgflag(DBG_SERVER,0,srv->id)," passwdcrypt = %s\n",passwdcrypt);
strcpy((char*)buf+index, (char*)passwdcrypt);
index+=strlen(passwdcrypt)+1;
if (ismultics) clicd.provid=0x0057484F;
if ( !cs_message_send(fd, &clicd, buf, index, sessionkey) ) return -1;
srv->ping = GetTickCount();
// 3.1 Get login answer
len = cs_message_receive(fd, &clicd, buf, sessionkey,15000);
if (len<3) {
static char msg[]= "Login error";
srv->statmsg = msg;
debugf(getdbgflag(DBG_SERVER,0,srv->id)," newcamd: login answer length error (%d) from server (%s:%d)\n",len, srv->host->name,srv->port);
return INVALID_SOCKET;
}
if ( buf[0] == MSG_CLIENT_2_SERVER_LOGIN_NAK ) {
static char msg[]= "Invalid user/pass";
srv->statmsg = msg;
debugf(getdbgflag(DBG_SERVER,0,srv->id)," newcamd: login failed to server (%s:%d)\n", srv->host->name,srv->port);
return -1;
}
else if( buf[0] != MSG_CLIENT_2_SERVER_LOGIN_ACK ) {
static char msg[]= "Login error";
srv->statmsg = msg;
debugf(getdbgflag(DBG_SERVER,0,srv->id)," newcamd: Error, expected MSG_CLIENT_2_SERVER_LOGIN_ACK\n");
return -1;
}
else debugf(getdbgflag(DBG_SERVER,0,srv->id)," newcamd: connect to server (%s:%d) user '%s'\n", srv->host->name, srv->port, srv->user);
// Ping
srv->ping = GetTickCount()-srv->ping;
// mgcamd protocol version?
if (clicd.sid==0x6E73) { //&&( (clicd.provid>>24)==0x14) ) {
if (ismultics) srv->progname = string_mgcamd_mcs;
else srv->progname = string_mgcamd;
}
else if (clicd.provid==0x004D4353) {
sprintf( srv->version, "r%d", clicd.sid);
srv->progname = string_newcamd_mcs;
}
else srv->progname = string_newcamd;
//
des_login_key_get( srv->key, (uint8_t*)passwdcrypt, strlen(passwdcrypt), sessionkey);
//debugdump(sessionkey,16,"sessionkey: ");
memcpy( srv->sessionkey, sessionkey,16);
// 4. Send MSG_CARD_DATA_REQ
memset( &clicd, 0, sizeof(clicd) );
clicd.msgid = 1;
buf[0]=MSG_CARD_DATA_REQ;
buf[1]=0; buf[2]=0;
if ( !cs_message_send(fd, &clicd, buf, 3, srv->sessionkey) ) return -1;
len = cs_message_receive( fd, NULL, buf, srv->sessionkey,5000);
if (len==0) {
static char msg[]= "Disconnected";
srv->statmsg = msg;
debugf(getdbgflag(DBG_SERVER,0,srv->id)," newcamd: client disconnected\n");
return INVALID_SOCKET;
}
else if (len<0) {
static char msg[]= "failed to receive card data";
srv->statmsg = msg;
debugf(getdbgflag(DBG_SERVER,0,srv->id)," newcamd: Error Recv MSG_CARD_DATA (%d)\n",len);
return INVALID_SOCKET;
}
if (buf[0]!=MSG_CARD_DATA) {
static char msg[]= "failed to receive card data";
srv->statmsg = msg;
debugf(getdbgflag(DBG_SERVER,0,srv->id)," newcamd: expected MSG_CARD_DATA\n");
return INVALID_SOCKET;
}
else if (len<15) {
debugf(getdbgflag(DBG_SERVER,0,srv->id)," newcamd: MSG_CARD_DATA, length error (%d)\n",len);
//return INVALID_SOCKET;
}
else {
// 5. Parse CAID and PROVID(s)
if ( (buf[14]<CARD_MAXPROV)&&(len>=(6+11*buf[14]))&&(buf[4]||buf[5]) ) { // CAID != 0x0000
struct cs_card_data *pcard = malloc( sizeof(struct cs_card_data) );
if (pcard) {
memset(pcard, 0, sizeof(struct cs_card_data) );
pcard->caid = ((buf[4]<<8) | buf[5]);
pcard->nbprov = buf[14];
pcard->uphops = 1;
//pcard->sids = NULL;
if (pcard->nbprov>CARD_MAXPROV) pcard->nbprov = CARD_MAXPROV;
debugf(getdbgflag(DBG_SERVER,0,srv->id)," newcamd: caid %04x providers %d\n", pcard->caid,buf[14]);
for( i=0; i<pcard->nbprov; i++ ) {
pcard->prov[i] = (buf[15+11*i]<<16)|(buf[16+11*i]<<8)|buf[17+11*i];
//debugf(getdbgflag(DBG_SERVER,0,srv->id)," newcamd: provider %02d = %06X\n", i+1, pcard->prov[i]);
}
pcard->next = srv->card;
srv->card = pcard;
}
else printf(" newcamd: failed to allocate memory\n");
} else debugf(getdbgflag(DBG_SERVER,0,srv->id)," newcamd: caid 0\n");
}
#ifdef CLI_CSCACHE
/* // Send keepalive Caching Check???
clicd.msgid = 0;
clicd.sid = ('C'<<8) | 'H';
clicd.caid = 0;
clicd.provid = 0;
buf[0] = MSG_KEEPALIVE;
buf[1] = 0;
buf[2] = 0;
cs_message_send(fd, &clicd, buf, 3, srv->sessionkey);
*/
srv->keepalive.status = GetTickCount();
srv->cscached = 0;
#endif
// Update Server data
static char msg[]= "Connected";
srv->statmsg = msg;
srv->connection.status = 1;
srv->connection.time = GetTickCount();
srv->keepalive.status = 0;
srv->keepalive.time = GetTickCount();
srv->busy = 0;
srv->lastecmoktime = 0;
srv->lastecmtime = 0;
srv->lastdcwtime = 0;
srv->chkrecvtime = 0;
srv->msg.len = 0;
srv->handle = fd;
#ifdef EPOLL_ECM
pipe_pointer( prg.pipe.ecm[1], PIPE_SRV_CONNECTED, srv );
#else
pipe_cmd( prg.pipe.ecm[1], PIPE_SRV_CONNECTED );
#endif
return 0;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
int cs_sendecm_srv(struct cardserver_data *cs, struct server_data *srv, ECM_DATA *ecm)
{
unsigned char buf[CWS_NETMSGSIZE];
struct cs_custom_data srvcd; // Custom data
srv->ecm.msgid++;
if (srv->ecm.msgid>0xfff) srv->ecm.msgid = 1;
srvcd.msgid = srv->ecm.msgid;
srvcd.sid = ecm->sid;
srvcd.caid = ecm->caid;
srvcd.provid = ecm->provid;
memcpy( &buf[0], &ecm->ecm[0], ecm->ecmlen );
return cs_message_send( srv->handle, &srvcd, buf, ecm->ecmlen, srv->sessionkey);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void cs_srv_recvmsg(struct server_data *srv)
{
struct cardserver_data *cs;
struct cs_custom_data srvcd; // Custom data
int len;
ECM_DATA *ecm;
unsigned char buf[CWS_NETMSGSIZE];
if ( (srv->handle<=0)||(srv->type!=TYPE_NEWCAMD) ) return;
len = cs_peekmsg( srv->handle, &srv->msg, srv->sessionkey, &srvcd, buf );
if (len==0) {
debugf(getdbgflag(DBG_SERVER,0,srv->id)," newcamd: server (%s:%d) read failed %d\n", srv->host->name, srv->port, len);
disconnect_srv(srv);
}
else if (len==-1) {
if (!srv->chkrecvtime) srv->chkrecvtime = GetTickCount();
else if ( (srv->chkrecvtime+300)<GetTickCount() ) {
debugf(getdbgflag(DBG_SERVER,0,srv->id)," newcamd: server (%s:%d) wrong data\n", srv->host->name, srv->port);
disconnect_srv(srv);
}
}
else if (len>0) {
srv->chkrecvtime = 0;
switch ( buf[0] ) {
case 0x80:
case 0x81:
srv->lastdcwtime = GetTickCount();
if (!srv->busy) {
debugf(getdbgflag(DBG_SERVER,0,srv->id)," [!] dcw error from server (%s:%d), unknown ecm request\n",srv->host->name,srv->port);
break;
}
srv->busy = 0;
pipe_cmd( prg.pipe.ecm[1], PIPE_SRV_AVAILABLE );
if (srvcd.msgid!=srv->ecm.msgid) {
debugf(getdbgflag(DBG_SERVER,0,srv->id)," [!] dcw error from server (%s:%d), wrong message-id!!!\n",srv->host->name,srv->port);
break;
}
pthread_mutex_lock(&prg.lockecm); //###
ecm = srv->ecm.request;
if (!ecm) {
debugf(getdbgflag(DBG_SERVER,0,srv->id)," [!] dcw error from server (%s:%d), ecm not found!!!\n",srv->host->name,srv->port);
pthread_mutex_unlock(&prg.lockecm); //###
break;
}
// check for ECM???
if (ecm->hash!=srv->ecm.hash) {
debugf(getdbgflag(DBG_SERVER,0,srv->id)," [!] dcw error from server (%s:%d), ecm deleted!!!\n",srv->host->name,srv->port);
pthread_mutex_unlock(&prg.lockecm); //###
break;
}
if (buf[2]==0x10) {
// Check for DCW
if (!acceptDCW(buf+3)) {
srv->ecmerrdcw ++;
pthread_mutex_unlock(&prg.lockecm); //###
break;
}
srv->ecmok++;
srv->lastecmoktime = GetTickCount()-srv->lastecmtime;
srv->ecmoktime += srv->lastecmoktime;
ecm_setsrvflagdcw( ecm, srv->id, ECM_SRV_REPLY_GOOD,buf+3 );
debugf(getdbgflagpro(DBG_SERVER,0,srv->id,ecm->cs->id)," <= cw from server (%s:%d) ch %04x:%06x:%04x (%dms)\n", srv->host->name,srv->port, ecm->caid,ecm->provid,ecm->sid, GetTickCount()-srv->lastecmtime);
if (ecm->dcwstatus!=STAT_DCW_SUCCESS) {
static char msg[] = "Good dcw from Newcamd server";
ecm->statusmsg = msg;
// Store ECM Answer
ecm_setdcw( ecm, buf+3, DCW_SOURCE_SERVER, srv->id );
}
else { //TODO: check same dcw between cards
srv->ecmerrdcw ++;
if ( memcmp(ecm->cw, buf+3, 16) ) debugf(getdbgflagpro(DBG_SERVER,0,srv->id,ecm->cs->id)," !!! different dcw from server (%s:%d)\n",srv->host->name,srv->port);
}
#ifdef SID_FILTER
// ADD IN SID LIST
cs= ecm->cs;
if (cs) {
cardsids_update( srv->busycard, ecm->provid, ecm->sid, 1);
srv_cstatadd( srv, cs->id, 1 , srv->lastecmoktime);
}
#endif
pthread_mutex_unlock(&prg.lockecm); //###
}
else {
cs= ecm->cs;
if ( cs && (ecm->dcwstatus!=STAT_DCW_SUCCESS) && (srv->retry<cs->option.retry.newcamd) ) {
if ( (GetTickCount()-ecm->recvtime) < (cs->option.server.timeout*ecm->period) ) {
srv->busy = 0;
if (cs_sendecm_srv(cs, srv, ecm)>0) {
srv->retry++;
ecm->lastsendtime = GetTickCount();
debugf(getdbgflagpro(DBG_SERVER,0,srv->id,ecm->cs->id)," (RE%d) -> ecm to server (%s:%d) ch %04x:%06x:%04x\n",srv->retry,srv->host->name,srv->port,ecm->caid,ecm->provid,ecm->sid);
srv->lastecmtime = GetTickCount();
srv->ecmnb++;
srv->busy = 1;
srv->ecm.request = ecm;
pthread_mutex_unlock(&prg.lockecm); //###
break;
}
}
}
ecm_setsrvflag(ecm, srv->id, ECM_SRV_REPLY_FAIL);
debugf(getdbgflagpro(DBG_SERVER,0,srv->id,ecm->cs->id)," <| decode failed from server (%s:%d) ch %04x:%06x:%04x (%dms)\n", srv->host->name,srv->port, ecm->caid,ecm->provid,ecm->sid, GetTickCount()-srv->lastecmtime);
#ifdef SID_FILTER
// ADD IN SID LIST
if (cs) {
cardsids_update( srv->busycard, ecm->provid, ecm->sid, -1);
srv_cstatadd( srv, cs->id, 0 , 0);
}
#endif
pthread_mutex_unlock(&prg.lockecm); //###
wakeup_sendecm(); // Wakeup ecm waiting for availabe servers
}
break;
// ADD CARD
// MSG_SERVER_2_CLIENT_REMOVECARD = 0xd4,
// MSG_SERVER_2_CLIENT_ADDCARD = 0xd3,
case 0xD3:
if (srvcd.caid) { // CAID != 0x0000
struct cs_card_data tcard;
memset(&tcard, 0, sizeof(struct cs_card_data) );
tcard.caid = srvcd.caid;
tcard.nbprov = 1;
tcard.prov[0] = srvcd.provid;
tcard.uphops = 1;
if ( tcard.uphops <= srv_sharelimits( srv, tcard.caid, srvcd.provid) ) {
debugf(getdbgflag(DBG_SERVER,0,srv->id)," Mgcamd: new card (%s:%d) caid %04x provider %06X\n", srv->host->name,srv->port, tcard.caid, tcard.prov[0]);
//debugf(getdbgflag(DBG_SERVER,0,srv->id)," Accepted %04x:%06x\n", tcard.caid, srvcd.provid);
struct cs_card_data *card = malloc( sizeof(struct cs_card_data) );
memcpy( card, &tcard, sizeof(struct cs_card_data) );
pthread_mutex_lock(&srv->lock); //###
card->next = srv->card;
srv->card = card;
pthread_mutex_unlock(&srv->lock); //###
}
//else debugf(getdbgflag(DBG_SERVER,0,srv->id)," Ignored %04x:%06x\n", tcard.caid, srvcd.provid);
}
break;
case 0xD4: // Delete Card
pthread_mutex_lock(&prg.lockecm); //###
struct cs_card_data *card = srv->card;
struct cs_card_data *prevcard = NULL;
while (card) {
if ( (card->caid==srvcd.caid)&&(card->prov[0]==srvcd.provid) ) {
debugf( getdbgflag(DBG_SERVER, 0, srv->id), " Mgcamd: server (%s:%d), remove card %04x:%06x\n",srv->host->name,srv->port, srvcd.caid, srvcd.provid);
if (prevcard) prevcard->next = card->next; else srv->card = card->next;
//Free SIDs
int s;
for(s=0; s<256; s++) {
struct sid_data *sid1 = card->sids[s];
while (sid1) {
struct sid_data *sid = sid1;
sid1 = sid1->next;
free(sid);
}
}
free(card);
// check for current ecm
/////XXX if (srv->busy && (srv->busycardid==k) ) ecm_setsrvflag(srv->ecm.request, srv->id, ECM_SRV_EXCLUDE);
break;
}
prevcard = card;
card = card->next;
}
pthread_mutex_unlock(&prg.lockecm); //###
break;
default:
if (buf[0]==MSG_KEEPALIVE) {
if (srv->keepalive.status) {
#ifdef CLI_CSCACHE
if ( ( srvcd.sid==(('C'<<8)|'H') ) && ( srvcd.caid==(('O'<<8)|'K') ) ) srv->cscached = 1;
#endif
srv->ping = GetTickCount() - srv->keepalive.time;
//debugf(getdbgflag(DBG_SERVER,0,srv->id)," <- keepalive from server (%s:%d) ping %dms\n",srv->host->name,srv->port,srv->ping);
srv->keepalive.status = 0;
}
//else debugf(getdbgflag(DBG_SERVER,0,srv->id)," <- Error keepalive from server (%s:%d)\n",srv->host->name,srv->port);
} else {
debugf(getdbgflag(DBG_SERVER,0,srv->id)," unknown message type '%02x' CAID:%04X PROVID:%06X from server (%s:%d)\n",buf[0],srvcd.caid,srvcd.provid,srv->host->name,srv->port);
}
}
srv->keepalive.time = GetTickCount();
}
}
void cs_check_keepalive(struct server_data *srv)
{
struct cs_custom_data clicd; // Custom data
unsigned char buf[CWS_NETMSGSIZE];
if ( (srv->handle<=0)||(srv->type!=TYPE_NEWCAMD) ) return;
// Check for sending keep alive
if (!srv->keepalive.status) {
if ( srv->keepalive.time+(KEEPALIVE_NEWCAMD*1000) < GetTickCount() ) {
buf[0] = MSG_KEEPALIVE;
buf[1] = 0;
buf[2] = 0;
//debugf(getdbgflag(DBG_SERVER,0,srv->id)," -> keepalive to server (%s:%d)\n",srv->host->name,srv->port);
if ( !cs_message_send( srv->handle, NULL, buf, 3, srv->sessionkey) ) {
disconnect_srv( srv );
}
else {
srv->keepalive.time = GetTickCount();
srv->keepalive.status = 1;
}
}
}
else {
if ( srv->keepalive.status+10000 < GetTickCount() ) { ///???
#ifdef CLI_CSCACHE
// Send keepalive Caching Check???
clicd.msgid = 0;
clicd.sid = ('C'<<8) | 'H';
clicd.caid = 0;
clicd.provid = 0;
buf[0] = MSG_KEEPALIVE;
buf[1] = 0;
buf[2] = 0;
srv->keepalive.status = GetTickCount();
if ( !cs_message_send( srv->handle, &clicd, buf, 3, srv->sessionkey) ) disconnect_srv( srv );
#else
debugf(getdbgflag(DBG_SERVER,0,srv->id)," ??? no keepalive response from server (%s:%d)\n",srv->host->name,srv->port);
srv->keepalive.status = 0;
#endif
}
}
}