int pandora_auth_client(struct s_client *cl, IN_ADDR_T ip) { int ok; struct s_auth *account; #ifdef IPV6SUPPORT // FIXME: Add IPv6 support (void)ip; // Prevent warning about unused var "ip" #else if (!cl->pand_ignore_ecm && cfg.pand_allowed) { struct s_ip *p_ip; for (ok = 0, p_ip = cfg.pand_allowed; (p_ip) && (!ok); p_ip = p_ip->next) ok = ((ip >= p_ip->ip[0]) && (ip <= p_ip->ip[1])); if (!ok) { cs_auth_client(cl, (struct s_auth *) 0, "IP not allowed"); return 0; } } #endif for (ok = 0, account = cfg.account; cfg.pand_usr && account && !ok; account = account->next) { ok = streq(cfg.pand_usr, account->usr); if (ok && cs_auth_client(cl, account, NULL)) cs_disconnect_client(cl); } if (!ok) cs_auth_client(cl, (struct s_auth *) (-1), NULL); return ok; }
static int32_t secmon_auth_client(uchar *ucrc) { uint32_t crc; struct s_auth *account; struct s_client *cur_cl = cur_client(); unsigned char md5tmp[MD5_DIGEST_LENGTH]; if (cur_cl->auth) { int32_t s=memcmp(cur_cl->ucrc, ucrc, 4); if (s) cs_log("wrong user-crc or garbage !?"); return !s; } cur_cl->crypted=1; crc=(ucrc[0]<<24) | (ucrc[1]<<16) | (ucrc[2]<<8) | ucrc[3]; for (account=cfg.account; (account) && (!cur_cl->auth); account=account->next) if ((account->monlvl) && (crc==crc32(0L, MD5((unsigned char *)account->usr, strlen(account->usr), md5tmp), MD5_DIGEST_LENGTH))) { memcpy(cur_cl->ucrc, ucrc, 4); aes_set_key(cur_cl, (char *)MD5((unsigned char *)ESTR(account->pwd), strlen(ESTR(account->pwd)), md5tmp)); if (cs_auth_client(cur_cl, account, NULL)) return -1; cur_cl->auth=1; } if (!cur_cl->auth) { cs_auth_client(cur_cl, (struct s_auth *)0, "invalid user"); return -1; } return cur_cl->auth; }
static void radegast_auth_client(IN_ADDR_T ip) { int32_t ok; struct s_auth *account; struct s_client *cl = cur_client(); ok = check_ip(cfg.rad_allowed, ip); if (!ok) { cs_log ("radegast: IP not allowed"); cs_auth_client(cl, (struct s_auth *)0, NULL); cs_disconnect_client(cl); } for (ok = 0, account = cfg.account; cfg.rad_usr && account && !ok; account = account->next) { ok = streq(cfg.rad_usr, account->usr); if (ok && cs_auth_client(cl, account, NULL)) cs_disconnect_client(cl); } if (!ok) cs_auth_client(cl, ok ? account : (struct s_auth *)(-1), "radegast"); }
static void radegast_auth_client(in_addr_t ip) { int32_t ok; struct s_auth *account; struct s_client *cl = cur_client(); ok = check_ip(cfg.rad_allowed, ip); if (!ok) { cs_log ("radegast: IP not allowed"); cs_auth_client(cl, (struct s_auth *)0, NULL); cs_disconnect_client(cl); } for (ok=0, account=cfg.account; (cfg.rad_usr[0]) && (account) && (!ok); account=account->next) { ok=(!strcmp(cfg.rad_usr, account->usr)); if (ok && cs_auth_client(cl, account, NULL)) cs_disconnect_client(cl); } if (!ok) cs_auth_client(cl, ok ? account : (struct s_auth *)(-1), "radegast"); }
static int8_t monitor_auth_client(char *usr, char *pwd) { struct s_auth *account; struct s_client *cur_cl = cur_client(); if (cur_cl->auth) return 0; if ((!usr) || (!pwd)) { cs_auth_client(cur_cl, (struct s_auth *)0, NULL); return -1; } for (account=cfg.account, cur_cl->auth=0; (account) && (!cur_cl->auth);) { if (account->monlvl) cur_cl->auth = streq(usr, account->usr) && streq(pwd, account->pwd); if (!cur_cl->auth) account=account->next; } if (!cur_cl->auth) { cs_auth_client(cur_cl, (struct s_auth *)0, "invalid account"); return -1; } if (cs_auth_client(cur_cl, account, NULL)) return -1; return 0; }
static int32_t camd35_auth_client(struct s_client *cl, uchar *ucrc) { int32_t rc = 1; uint32_t crc; struct s_auth *account; unsigned char md5tmp[MD5_DIGEST_LENGTH]; if(cl->upwd[0]) { return (memcmp(cl->ucrc, ucrc, 4) ? 1 : 0); } cl->crypted = 1; crc = (((ucrc[0] << 24) | (ucrc[1] << 16) | (ucrc[2] << 8) | ucrc[3]) & 0xffffffffL); for(account = cfg.account; (account) && (!cl->upwd[0]); account = account->next) if(crc == crc32(0L, MD5((unsigned char *)account->usr, strlen(account->usr), md5tmp), MD5_DIGEST_LENGTH)) { rc = cs_auth_client(cl, account, NULL); if(!rc) { memcpy(cl->ucrc, ucrc, 4); cs_strncpy((char *)cl->upwd, account->pwd, sizeof(cl->upwd)); if (!aes_set_key_alloc(&cl->aes_keys, (char *) MD5(cl->upwd, strlen((char *)cl->upwd), md5tmp))) { return 1; } return 0; } } return (rc); }
static int8_t monitor_check_ip(void) { int32_t ok=0; struct s_client *cur_cl = cur_client(); if (cur_cl->auth) return 0; ok = check_ip(cfg.mon_allowed, cur_cl->ip); if (!ok) { cs_auth_client(cur_cl, (struct s_auth *)0, "invalid ip"); return -1; } return 0; }
static void radegast_auth_client(in_addr_t ip) { int32_t ok; struct s_auth *account; ok = check_ip(cfg.rad_allowed, ip); if (!ok) { cs_auth_client(cur_client(), (struct s_auth *)0, NULL); cs_exit(0); } for (ok=0, account=cfg.account; (cfg.rad_usr[0]) && (account) && (!ok); account=account->next) { ok=(!strcmp(cfg.rad_usr, account->usr)); if (ok && cs_auth_client(cur_client(), account, NULL)) cs_exit(0); } if (!ok) cs_auth_client(cur_client(), (struct s_auth *)(-1), NULL); }
static void gbox_auth_client(struct s_client *cli) { struct s_client *cl = switch_client_proxy(cli); if(cl->typ == 'p' && cl->gbox && cl->reader) { cli->crypted = 1; //display as crypted cli->gbox = cl->gbox; //point to the same gbox as proxy cli->reader = cl->reader; //point to the same reader as proxy struct s_auth *account = get_account_by_name(gbox_username(cl)); if(account) { cs_auth_client(cli, account, NULL); cli->account = account; cli->grp = account->grp; } } return ; }
static void oscam_ser_auth_client(int32_t proto) { int32_t ok = 0; struct s_serial_client *serialdata=cur_client()->serialdata; // After reload base account ptrs may be placed in other address, // and we may can't find it in this process. // Simply save valid account. struct s_auth *account=0; if (serialdata->connected==proto) return; if (serialdata->connected) oscam_ser_disconnect(); serialdata->connected=proto; for (ok=0, account=cfg.account; (account) && (!ok); account=account->next) if( (ok=!strcmp(serialdata->oscam_ser_usr, account->usr)) ) break; cs_auth_client(cur_client(), ok ? account : (struct s_auth *)(-1), proto_txt[serialdata->connected]); }
static int32_t camd35_auth_client(struct s_client *cl, uchar *ucrc) { int32_t rc = 1, no_delay = 1; uint32_t crc; struct s_auth *account; unsigned char md5tmp[MD5_DIGEST_LENGTH]; if(cl->upwd[0]) { return (memcmp(cl->ucrc, ucrc, 4) ? 1 : 0); } cl->crypted = 1; crc = (((ucrc[0] << 24) | (ucrc[1] << 16) | (ucrc[2] << 8) | ucrc[3]) & 0xffffffffL); for(account = cfg.account; (account) && (!cl->upwd[0]); account = account->next) if(crc == crc32(0L, MD5((unsigned char *)account->usr, strlen(account->usr), md5tmp), MD5_DIGEST_LENGTH)) { rc = cs_auth_client(cl, account, NULL); if(!rc) { memcpy(cl->ucrc, ucrc, 4); cs_strncpy((char *)cl->upwd, account->pwd, sizeof(cl->upwd)); if (!aes_set_key_alloc(&cl->aes_keys, (char *) MD5(cl->upwd, strlen((char *)cl->upwd), md5tmp))) { return 1; } #ifdef CS_CACHEEX if(cl->account->cacheex.mode < 2) #endif if(!cl->is_udp && cl->tcp_nodelay == 0) { setsockopt(cl->udp_fd, IPPROTO_TCP, TCP_NODELAY, (void *)&no_delay, sizeof(no_delay)); cl->tcp_nodelay = 1; } return 0; } } return (rc); }
static int32_t camd35_recv(struct s_client *client, uchar *buf, int32_t l) { int32_t rc, s, rs, n = 0, buflen = 0, len = 0; for(rc = rs = s = 0; !rc; s++) { switch(s) { case 0: if(!client->udp_fd) { return (-9); } if(client->is_udp && client->typ == 'c') { rs = recv_from_udpipe(buf); } else { //read minimum packet size (4 byte ucrc + 32 byte data) to detect packet size (tcp only) //rs = cs_recv(client->udp_fd, buf, client->is_udp ? l : 36, 0); if(client->is_udp){ while (1){ rs = cs_recv(client->udp_fd, buf, l, 0); if (rs < 0){ if(errno == EINTR) { continue; } // try again in case of interrupt if(errno == EAGAIN) { continue; } //EAGAIN needs select procedure again cs_log_dbg(client->typ == 'c' ? D_CLIENT : D_READER, "ERROR: %s (errno=%d %s)", __func__, errno, strerror(errno)); break; }else {break;} } }else{ int32_t tot=36, readed=0; rs = 0; do { readed = cs_recv(client->udp_fd, buf+rs, tot, 0); if (readed < 0){ if(errno == EINTR) { continue; } // try again in case of interrupt if(errno == EAGAIN) { continue; } //EAGAIN needs select procedure again cs_log_dbg(client->typ == 'c' ? D_CLIENT : D_READER, "ERROR: %s (errno=%d %s)", __func__, errno, strerror(errno)); break; } if (readed == 0){ // nothing to read left! rc = -5; break; } if (readed > 0){ // received something, add it! tot-=readed; rs+=readed; } } while(tot!=0); } } if(rs < 36) { if(rc != -5) { rc = -1; } goto out; } break; case 1: switch(camd35_auth_client(client, buf)) { case 0: break; // ok case 1: rc = -2; break; // unknown user default: rc = -9; break; // error's from cs_auth() } memmove(buf, buf + 4, rs -= 4); break; case 2: aes_decrypt(client->aes_keys, buf, rs); if(rs != boundary(4, rs)) cs_log_dbg(client->typ == 'c' ? D_CLIENT : D_READER, "WARNING: packet size has wrong decryption boundary"); n = (buf[0] == 3) ? 0x34 : 0; //Fix for ECM request size > 255 (use ecm length field) if(buf[0] == 0) { buflen = (((buf[21] & 0x0f) << 8) | buf[22]) + 3; } else if(buf[0] == 0x3d || buf[0] == 0x3e || buf[0] == 0x3f) //cacheex-push { buflen = buf[1] | (buf[2] << 8); } else { buflen = buf[1]; } n = boundary(4, n + 20 + buflen); if(!(client->is_udp && client->typ == 'c') && (rs < n) && ((n - 32) > 0)) { //len = cs_recv(client->udp_fd, buf+32, n-32, 0); // read the rest of the packet int32_t tot=n-32, readed=0; len = 0; do{ readed = cs_recv(client->udp_fd, buf+32+len, tot, 0); // read the rest of the packet if (readed < 0){ if(errno == EINTR) { continue; } // try again in case of interrupt if(errno == EAGAIN) { continue; } //EAGAIN needs select procedure again cs_log_dbg(client->typ == 'c' ? D_CLIENT : D_READER, "ERROR: %s (errno=%d %s)", __func__, errno, strerror(errno)); break; } if (readed == 0){ // nothing to read left! break; } if (readed > 0){ // received something, add it! tot-=readed; len+=readed; } } while(tot!=0); if(len > 0) { rs += len; aes_decrypt(client->aes_keys, buf + 32, len); } if(len < 0) { rc = -1; goto out; } } cs_log_dump_dbg(client->typ == 'c' ? D_CLIENT : D_READER, buf, rs, "received %d bytes from %s", rs, remote_txt()); if(n < rs) cs_log_dbg(client->typ == 'c' ? D_CLIENT : D_READER, "ignoring %d bytes of garbage", rs - n); else if(n > rs) { rc = -3; } break; case 3: if(crc32(0L, buf + 20, buflen) != b2i(4, buf + 4)) { rc = -4; } if(!rc) { rc = n; } break; } } out: if((rs > 0) && ((rc == -1) || (rc == -2))) { cs_log_dump_dbg(client->typ == 'c' ? D_CLIENT : D_READER, buf, rs, "received %d bytes from %s (native)", rs, remote_txt()); } if(rc >= 0) { client->last = time(NULL); } // last client action is now switch(rc) { //case 0: break; case -1: cs_log("packet is too small (received %d bytes, expected %d bytes)", rs, l); break; case -2: if(cs_auth_client(client, 0, "unknown user")) { cs_disconnect_client(client); } break; case -3: cs_log("incomplete request !"); break; case -4: cs_log("checksum error (wrong password ?)"); break; case -5: cs_log_dbg(client->typ == 'c' ? D_CLIENT : D_READER, "connection closed"); break; //default: cs_log_dbg(D_TRACE, "camd35_recv returns rc=%d", rc); break; } return (rc); }
void * azbox_main_thread(void *cli) { struct s_client * client = (struct s_client *) cli; client->thread=pthread_self(); pthread_setspecific(getclient, cli); dvbapi_client=cli; struct s_auth *account; int32_t ok = 0; for (account = cfg.account; account; account=account->next) { if ((ok = streq(cfg.dvbapi_usr, account->usr))) break; } cs_auth_client(client, ok ? account : (struct s_auth *)(-1), "dvbapi"); dvbapi_read_priority(); openxcas_msg_t msg; int32_t ret; while ((ret = openxcas_get_message(&msg, 0)) >= 0) { cs_sleepms(10); if (ret) { openxcas_stream_id = msg.stream_id; openxcas_seq = msg.sequence; switch(msg.cmd) { case OPENXCAS_SELECT_CHANNEL: cs_debug_mask(D_DVBAPI, LOG_PREFIX_MSG "OPENXCAS_SELECT_CHANNEL"); // parse channel info struct stOpenXCASChannel chan; memcpy(&chan, msg.buf, msg.buf_len); cs_log(LOG_PREFIX "channel change: sid = %x, vpid = %x. apid = %x", chan.service_id, chan.v_pid, chan.a_pid); openxcas_video_pid = chan.v_pid; openxcas_audio_pid = chan.a_pid; openxcas_data_pid = chan.d_pid; break; case OPENXCAS_START_PMT_ECM: cs_debug_mask(D_DVBAPI, LOG_PREFIX_MSG "OPENXCAS_START_PMT_ECM"); // parse pmt uchar *dest; if (!cs_malloc(&dest, msg.buf_len + 7 - 12 - 4)) break; memcpy(dest, "\x00\xFF\xFF\x00\x00\x13\x00", 7); dest[1] = msg.buf[3]; dest[2] = msg.buf[4]; dest[5] = msg.buf[11]+1; memcpy(dest + 7, msg.buf + 12, msg.buf_len - 12 - 4); dvbapi_parse_capmt(dest, 7 + msg.buf_len - 12 - 4, -1, NULL); free(dest); unsigned char mask[12]; unsigned char comp[12]; memset(&mask, 0x00, sizeof(mask)); memset(&comp, 0x00, sizeof(comp)); mask[0] = 0xfe; comp[0] = 0x80; if ((ret = openxcas_add_filter(msg.stream_id, OPENXCAS_FILTER_ECM, 0, 0xffff, openxcas_ecm_pid, mask, comp, (void *)azbox_openxcas_ecm_callback)) < 0) cs_log(LOG_PREFIX "unable to add ecm filter"); else cs_debug_mask(D_DVBAPI, LOG_PREFIX "ecm filter added, pid = %x, caid = %x", openxcas_ecm_pid, 0); if (openxcas_start_filter(msg.stream_id, msg.sequence, OPENXCAS_FILTER_ECM) < 0) cs_log(LOG_PREFIX "unable to start ecm filter"); else cs_debug_mask(D_DVBAPI, LOG_PREFIX "ecm filter started"); if (!openxcas_create_cipher_ex(msg.stream_id, openxcas_seq, 0, openxcas_ecm_pid, openxcas_video_pid, 0xffff, openxcas_audio_pid, 0xffff, 0xffff, 0xffff)) cs_log(LOG_PREFIX "failed to create cipher ex"); else cs_debug_mask(D_DVBAPI, LOG_PREFIX "cipher created"); break; case OPENXCAS_STOP_PMT_ECM: cs_debug_mask(D_DVBAPI, LOG_PREFIX_MSG "OPENXCAS_STOP_PMT_ECM"); openxcas_stop_filter(msg.stream_id, OPENXCAS_FILTER_ECM); openxcas_remove_filter(msg.stream_id, OPENXCAS_FILTER_ECM); openxcas_stop_filter_ex(msg.stream_id, msg.sequence, openxcas_filter_idx); openxcas_destory_cipher_ex(msg.stream_id, msg.sequence); memset(&demux, 0, sizeof(demux)); break; case OPENXCAS_ECM_CALLBACK: cs_debug_mask(D_DVBAPI, LOG_PREFIX_MSG "OPENXCAS_ECM_CALLBACK"); struct stOpenXCAS_Data data; memcpy(&data, msg.buf, msg.buf_len); if (!openxcas_busy) openxcas_filter_callback(msg.stream_id, msg.sequence, OPENXCAS_FILTER_ECM, &data); break; case OPENXCAS_PID_FILTER_CALLBACK: cs_debug_mask(D_DVBAPI, LOG_PREFIX_MSG "OPENXCAS_PID_FILTER_CALLBACK"); openxcas_filter_callback_ex(msg.stream_id, msg.sequence, (struct stOpenXCAS_Data *)msg.buf); break; case OPENXCAS_QUIT: cs_debug_mask(D_DVBAPI, LOG_PREFIX_MSG "OPENXCAS_QUIT"); openxcas_close(); cs_log(LOG_PREFIX "exited"); return NULL; break; case OPENXCAS_UKNOWN_MSG: default: cs_debug_mask(D_DVBAPI, LOG_PREFIX_MSG "OPENXCAS_UKNOWN_MSG (%d)", msg.cmd); //cs_ddump_mask(D_DVBAPI, &msg, sizeof(msg), "msg dump:"); break; } } } cs_log(LOG_PREFIX "invalid message"); return NULL; }