./ MultiCS.r69 / srv-freecccam.c
/////////////////////////////////////////////////////////////////////////////// // File: srv-freecccam.c /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // PROTO /////////////////////////////////////////////////////////////////////////////// void freecc_cli_recvmsg(struct cc_client_data *cli); /////////////////////////////////////////////////////////////////////////////// // FREECCCAM SERVER: CONNECT CLIENTS /////////////////////////////////////////////////////////////////////////////// void frcc_sendcards_cli(struct cc_client_data *cli) { int nbcard=0; struct cardserver_data *cs = cfg.cardserver; int i; if (cfg.freecccam.csport[0]) { for(i=0;i<MAX_CSPORTS;i++) { if(cfg.freecccam.csport[i]) { cs = getcsbyport(cfg.freecccam.csport[i]); if (cs) if (cc_sendcard_cli(cs, cli,0)) nbcard++; } else break; } } else { while (cs) { if (cc_sendcard_cli(cs, cli,0)) nbcard++; cs = cs->next; } } debugf(" FreeCCcam: %d cards --> client(%s)\n", nbcard, ip2string(cli->ip) ); } /////////////////////////////////////////////////////////////////////////////// struct freecc_connect_cli_data { int sock; uint32 ip; }; void *freecc_connect_cli(struct freecc_connect_cli_data *param) { uint8 buf[CC_MAXMSGSIZE]; uint8 data[16]; int i; struct cc_crypt_block sendblock; // crypto state block struct cc_crypt_block recvblock; // crypto state block char usr[64]; char pwd[255]; int sock = param->sock; uint32 ip = param->ip; free(param); memset(usr, 0, sizeof(usr)); memset(pwd, 0, sizeof(pwd)); // create & send random seed for(i=0; i<12; i++ ) data[i]=fast_rnd(); // Create Multics ID data[3] = (data[0]^'M') + data[1] + data[2]; data[7] = data[4] + (data[5]^'C') + data[6]; data[11] = data[8] + data[9] + (data[10]^'S'); //Create checksum for "O" cccam: for (i = 0; i < 4; i++) { data[12 + i] = (data[i] + data[4 + i] + data[8 + i]) & 0xff; } send_nonb(sock, data, 16, 100); //XOR init bytes with 'CCcam' cc_crypt_xor(data); //SHA1 SHA_CTX ctx; SHA1_Init(&ctx); SHA1_Update(&ctx, data, 16); SHA1_Final(buf, &ctx); //initialisate crypto states cc_crypt_init(&sendblock, buf, 20); cc_decrypt(&sendblock, data, 16); cc_crypt_init(&recvblock, data, 16); cc_decrypt(&recvblock, buf, 20); //debugdump(buf, 20, "SHA1 hash:"); memcpy(usr,buf,20); if ((i=recv_nonb(sock, buf, 20,3000)) == 20) { cc_decrypt(&recvblock, buf, 20); //debugdump(buf, 20, "Recv SHA1 hash:"); if ( memcmp(buf,usr,20)!=0 ) { //debugf(" cc_connect_cli(): wrong sha1 hash from client! (%s)\n",ip2string(ip)); close(sock); return NULL; } } else { //debugf(" cc_connect_cli(): recv sha1 timeout\n"); close(sock); return NULL; } // receive username if ((i=recv_nonb(sock, buf, 20,3000)) == 20) { cc_decrypt(&recvblock, buf, i); memcpy(usr,buf,20); //debugf(" cc_connect_cli(): username '%s'\n", usr); } else { //debugf(" cc_connect_cli(): recv user timeout\n"); close(sock); return NULL; } // Check for username pthread_mutex_lock(&prg.lockfreecccli); int found = 0; struct cc_client_data *cli = cfg.freecccam.server.client; while (cli) { if (!strcmp(cfg.freecccam.user,usr)) { if (cli->handle<=0) { found = 1; break; } else { if (cli->ip == ip) { // dont connect cc_disconnect_cli(cli); found = 1; break; } } } cli = cli->next; } if (!found) while (cli) { if (!strcmp(cfg.freecccam.user,usr)) { if (cli->handle>0) { // Check if we can disconnect idle state clients if (GetTickCount()-cli->lastecmtime > 100000) cc_disconnect_cli(cli); } if (cli->handle<=0) { found = 1; break; } } cli = cli->next; } pthread_mutex_unlock(&prg.lockfreecccli); if (!found) { debugf(" FreeCCcam: Failed to connect new client(%s)\n",ip2string(ip)); close(sock); return NULL; } // receive passwd / 'CCcam' if ((i=recv_nonb(sock, buf, 6,3000)) == 6) { memset(pwd, 0, sizeof(pwd)); strcpy( pwd, cfg.freecccam.pass); cc_encrypt(&recvblock, (uint8*)pwd, strlen(pwd)); cc_decrypt(&recvblock, buf, 6); if (memcmp( buf, "CCcam\0",6)) { debugf(" FreeCCcam: login failed from client(%s)\n",ip2string(ip)); close(sock); return NULL; } } else { close(sock); return NULL; } // send passwd ack memset(buf, 0, 20); memcpy(buf, "CCcam\0", 6); //debugf("Server: send ack '%s'\n",buf); cc_encrypt(&sendblock, buf, 20); send_nonb(sock, buf, 20, 100); sprintf(cli->user,"%s", ip2string(ip)); //cli->ecmnb=0; //cli->ecmok=0; memcpy(&cli->sendblock,&sendblock,sizeof(sendblock)); memcpy(&cli->recvblock,&recvblock,sizeof(recvblock)); debugf(" FreeCCcam: client(%s) connected\n",ip2string(ip)); // recv cli data memset(buf, 0, sizeof(buf)); i = cc_msg_recv( sock, &cli->recvblock, buf, 3000); if (i!=97) { debug("error recv cli data\n"); close(sock); return NULL; } // Setup Client Data // pthread_mutex_lock(&prg.lockfreecccli); memcpy( cli->nodeid, buf+24, 8); memcpy( cli->version, buf+33, 32); memcpy( cli->build, buf+65, 32 ); debugf(" FreeCCcam: client(%s) running version %s build %s\n",ip2string(ip), cli->version, cli->build); // cli->nodeid,8, cli->cardsent = 0; cli->connected = GetTickCount(); cli->lastecmtime = GetTickCount(); cli->handle = sock; cli->ip = ip; cli->chkrecvtime = 0; // Delete ECM REQUEST cli->ecm.busy = 0; // pthread_mutex_unlock(&prg.lockfreecccli); // send cli data ack cc_msg_send( sock, &cli->sendblock, CC_MSG_CLI_INFO, 0, NULL); //cc_msg_send( sock, &cli->sendblock, CC_MSG_BAD_ECM, 0, NULL); int sendversion = ( (cli->version[28]=='W')&&(cli->version[29]='H')&&(cli->version[30]='O') ); cc_sendinfo_cli(cli, sendversion); //cc_msg_send( sock, &cli->sendblock, CC_MSG_BAD_ECM, 0, NULL); cli->cardsent = 1; usleep(10000); frcc_sendcards_cli(cli); pipe_wakeup( srvsocks[1] ); return cli; } void *freecc_connect_cli_thread(void *param) { SOCKET client_sock =-1; struct sockaddr_in client_addr; socklen_t socklen = sizeof(client_addr); pthread_t srv_tid; while(1) { pthread_mutex_lock(&prg.locksrvfreecc); if (cfg.freecccam.server.handle>0) { struct pollfd pfd; pfd.fd = cfg.freecccam.server.handle; pfd.events = POLLIN | POLLPRI; int retval = poll(&pfd, 1, 3000); if ( retval>0 ) { client_sock = accept( cfg.freecccam.server.handle, (struct sockaddr*)&client_addr, /*(socklen_t*)*/&socklen); if ( client_sock<0 ) { debugf(" FreeCCcam: Accept failed (errno=%d)\n",errno); usleep(30000); } else { //debugf(" FreeCCcam: new connection...\n"); struct freecc_connect_cli_data *clicondata = malloc( sizeof(struct freecc_connect_cli_data) ); SetSocketKeepalive(client_sock); clicondata->sock = client_sock; clicondata->ip = client_addr.sin_addr.s_addr; create_prio_thread(&srv_tid, (threadfn)freecc_connect_cli,clicondata, 50); } } else if (retval<0) usleep(30000); } else usleep(100000); pthread_mutex_unlock(&prg.locksrvfreecc); usleep(3000); }// While } // Receive messages from clients void freecc_cli_recvmsg(struct cc_client_data *cli) { unsigned char buf[CC_MAXMSGSIZE]; unsigned char data[CC_MAXMSGSIZE]; // for other use unsigned int cardid; int len; if (cli->handle>0) { len = cc_msg_chkrecv(cli->handle,&cli->recvblock); if (len==0) { debugf(" FreeCCcam: client(%s) read failed %d\n", cli->user,len); cc_disconnect_cli(cli); } else if (len==-1) { if (!cli->chkrecvtime) cli->chkrecvtime = GetTickCount(); else if ( (cli->chkrecvtime+500)<GetTickCount() ) { debugf(" FreeCCcam: client(%s) read failed %d\n", cli->user,len); cc_disconnect_cli(cli); } } else if (len>0) { cli->chkrecvtime = 0; len = cc_msg_recv( cli->handle, &cli->recvblock, buf, 3); if (len==0) { debugf(" FreeCCcam: client(%s) read failed %d\n", cli->user,len); cc_disconnect_cli(cli); } else if (len<0) { debugf(" FreeCCcam: client(%s) read failed %d(%d)\n", cli->user,len,errno); cc_disconnect_cli(cli); } else if (len>0) { switch (buf[1]) { case CC_MSG_ECM_REQUEST: // Check for length cli->lastecmtime = GetTickCount(); if (cli->ecm.busy) { // send decode failed debugf(" <|> decode failed to CCcam client(%s), too many ecm requests\n", cli->user); break; } //Check for card availability memcpy( data, buf+17, len-17); cardid = buf[10]<<24 | buf[11]<<16 | buf[12]<<8 | buf[13]; uint16 caid = buf[4]<<8 | buf[5]; uint16 sid = buf[14]<<8 | buf[15]; uint32_t provid = ecm_getprovid( data, caid ); if (provid==0) provid = buf[6]<<24 | buf[7]<<16 | buf[8]<<8 | buf[9]; // Check for Profile struct cardserver_data *cs=getcsbyid( cardid ); if (!cs) { cli->ecmdenied++; cc_msg_send( cli->handle, &cli->sendblock, CC_MSG_ECM_NOK2, 0, NULL); debugf(" <|> decode failed to CCcam client(%s), card-id %x not found\n", cli->user, cardid); break; } // profile Acception char *error = cs_accept_ecm(cs,caid,provid,sid,ecm_getchid(data,caid)); if (error) { cs->ecmdenied++; cli->ecmdenied++; cc_msg_send( cli->handle, &cli->sendblock, CC_MSG_ECM_NOK2, 0, NULL); debugf(" <|> decode failed to CCcam client(%s), %s\n", cli->user,error); break; } // Check ECM length if ( !accept_ecmlen(len) ) { cli->ecmdenied++; cs->ecmdenied++; buf[1] = 0; buf[2] = 0; cc_msg_send( cli->handle, &cli->sendblock, CC_MSG_ECM_NOK2, 0, NULL); debugf(" <|> decode failed to CCcam client(%s) ch %04x:%06x:%04x, ecm length error(%d)\n", cli->user,caid,provid,sid,len); break; } // ACCEPTED pthread_mutex_lock(&prg.lockecm); // Search for ECM int ecmid = search_ecmdata_dcw( data, len-17, sid); // dont get failed ecm request from cache if ( ecmid!=-1 ) { ECM_DATA *ecm=getecmbyid(ecmid); ecm->lastrecvtime = GetTickCount(); //TODO: Add another card for sending ecm cc_store_ecmclient(ecmid, cli); debugf(" <- ecm from CCcam client(%s) ch %04x:%06x:%04x*\n", cli->user, caid, provid, sid); cli->ecm.busy=1; cli->ecm.hash = ecm->hash; cli->ecm.cardid = cs->id; } else { cs->ecmaccepted++; // Setup ECM Request for Server(s) ecmid = store_ecmdata(cs->id, &data[0], len-17, sid, caid, provid); ECM_DATA *ecm=getecmbyid(ecmid); cc_store_ecmclient(ecmid, cli); debugf(" <- ecm from CCcam client(%s) ch %04x:%06x:%04x (>%dms)\n", cli->user,caid,provid,sid, cli->ecm.dcwtime); cli->ecm.busy=1; cli->ecm.hash = ecm->hash; cli->ecm.cardid = cs->id; if (cs->option.fallowcache && cfg.cache.peer) { pipe_send_cache_find(ecm, cs); ecm->waitcache = 1; ecm->dcwstatus = STAT_DCW_WAITCACHE; } else ecm->dcwstatus = STAT_DCW_WAIT; } ecm_check_time = frcc_dcw_check_time = 0; pthread_mutex_unlock(&prg.lockecm); break; case CC_MSG_KEEPALIVE: //printf(" Keepalive from client '%s'\n",cli->user); cc_msg_send( cli->handle, &cli->sendblock, CC_MSG_KEEPALIVE, 0, NULL); break; case CC_MSG_BAD_ECM: //debugf(" CCcam: cmd 0x05 ACK from client '%s'\n",cli->user); //if (cli->cardsent==0) { // cc_sendcards_cli(cli); // cli->cardsent=1; //} break; //default: debugf(" FreeCCcam: Unknown Packet ID : %02x from client(%s)\n", buf[1], cli->user); } } } } } // Check sending cw to clients uint32 freecc_check_sendcw() { struct cc_client_data *cli = cfg.freecccam.server.client; uint ticks = GetTickCount(); uint restime = ticks + 10000; uint clitime = restime; while (cli) { if ( (cli->handle!=INVALID_SOCKET)&&(cli->ecm.busy) ) { //&&(cli->ecm.status==STAT_ECM_SENT) ) { pthread_mutex_lock(&prg.lockecm); //### // Check for DCW ANSWER ECM_DATA *ecm = getecmbyid(cli->ecm.id); if (ecm->hash!=cli->ecm.hash) cc_senddcw_cli( cli ); // Check for FAILED if (ecm->dcwstatus==STAT_DCW_FAILED) { static char msg[] = "decode failed"; cli->ecm.statmsg=msg; cc_senddcw_cli( cli ); } // Check for SUCCESS else if (ecm->dcwstatus==STAT_DCW_SUCCESS) { // check for client allowed cw time if ( (cli->ecm.recvtime+cli->ecm.dcwtime)<=ticks ) { static char msg[] = "good dcw"; cli->ecm.statmsg = msg; cc_senddcw_cli( cli ); } else clitime = cli->ecm.recvtime+cli->ecm.dcwtime; } // check for timeout / no server again else if (ecm->dcwstatus==STAT_DCW_WAIT){ uint32 timeout; struct cardserver_data *cs = getcsbyid( ecm->csid); if (cs) timeout = cs->option.dcw.timeout; else timeout = 5700; if ( (cli->ecm.recvtime+timeout) < ticks ) { static char msg[] = "dcw timeout"; cli->ecm.statmsg=msg; cc_senddcw_cli( cli ); } else clitime = cli->ecm.recvtime+timeout; } if (restime>clitime) restime = clitime; pthread_mutex_unlock(&prg.lockecm); //### } cli = cli->next; } return (restime+1); }