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 __camd35_send(struct s_client *cl, uchar *buf, int32_t buflen, int answer_awaited) { int32_t l; unsigned char rbuf[REQ_SIZE + 15 + 4], *sbuf = rbuf + 4; if(!cl->udp_fd || !cl->crypted) { return (-1); } //exit if no fd or aes key not set! //Fix ECM len > 255 if(buflen <= 0) { buflen = ((buf[0] == 0) ? (((buf[21] & 0x0f) << 8) | buf[22]) + 3 : buf[1]); } l = 20 + (((buf[0] == 3) || (buf[0] == 4)) ? 0x34 : 0) + buflen; memcpy(rbuf, cl->ucrc, 4); memcpy(sbuf, buf, l); memset(sbuf + l, 0xff, 15); // set unused space to 0xff for newer camd3's i2b_buf(4, crc32(0L, sbuf + 20, buflen), sbuf + 4); l = boundary(4, l); cs_log_dump_dbg(cl->typ == 'c' ? D_CLIENT : D_READER, sbuf, l, "send %d bytes to %s", l, username(cl)); aes_encrypt_idx(cl->aes_keys, sbuf, l); int32_t status; if(cl->is_udp) { status = sendto(cl->udp_fd, rbuf, l + 4, 0, (struct sockaddr *)&cl->udp_sa, cl->udp_sa_len); if(status == -1) { set_null_ip(&SIN_GET_ADDR(cl->udp_sa)); } } else { status = send(cl->udp_fd, rbuf, l + 4, 0); if(cl->typ == 'p' && cl->reader) { if(status == -1) { network_tcp_connection_close(cl->reader, "can't send"); } } else if(cl->typ == 'c') { if(status == -1) { cs_disconnect_client(cl); } } } if(status != -1) { if(cl->reader && answer_awaited) { cl->reader->last_s = time(NULL); } if(cl->reader && !answer_awaited) { cl->reader->last_s = cl->reader->last_g = time(NULL); } cl->last = time(NULL); } return status; }
static void monitor_login(char *usr){ char *pwd=NULL; int8_t res = 0; if ((usr) && (pwd=strchr(usr, ' '))) *pwd++=0; if (pwd) res = monitor_auth_client(trim(usr), trim(pwd)); else res = monitor_auth_client(NULL, NULL); if (res == -1) { cs_disconnect_client(cur_client()); return; } monitor_send_login(); }
static void * radegast_server(void *cli) { int32_t n; uchar mbuf[1024]; struct s_client * client = (struct s_client *) cli; client->thread=pthread_self(); pthread_setspecific(getclient, cli); radegast_auth_client(cur_client()->ip); while ((n=get_request(mbuf))>0) { switch(mbuf[0]) { case 1: radegast_process_ecm(mbuf+2, mbuf[1]); break; default: radegast_process_unknown(mbuf); } } cs_disconnect_client(client); return NULL; }
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); }
static void cs_fake_client(struct s_client *client, char *usr, int32_t uniq, IN_ADDR_T ip) { /* Uniq = 1: only one connection per user * * Uniq = 2: set (new connected) user only to fake if source * ip is different (e.g. for newcamd clients with * different CAID's -> Ports) * * Uniq = 3: only one connection per user, but only the last * login will survive (old mpcs behavior) * * Uniq = 4: set user only to fake if source ip is * different, but only the last login will survive */ struct s_client *cl; struct s_auth *account; cs_writelock(&fakeuser_lock); for (cl = first_client->next; cl; cl = cl->next) { account = cl->account; if (cl != client && cl->typ == 'c' && !cl->dup && account && streq(account->usr, usr) && uniq < 5 && ((uniq % 2) || !IP_EQUAL(cl->ip, ip))) { char buf[20]; if (uniq == 3 || uniq == 4) { cl->dup = 1; cl->aureader_list = NULL; cs_strncpy(buf, cs_inet_ntoa(cl->ip), sizeof(buf)); cs_log("client(%8lX) duplicate user '%s' from %s (prev %s) set to fake (uniq=%d)", (unsigned long)cl->thread, usr, cs_inet_ntoa(ip), buf, uniq); if (cl->failban & BAN_DUPLICATE) { cs_add_violation(cl, usr); } if (cfg.dropdups) { cs_writeunlock(&fakeuser_lock); cs_sleepms(100); // sleep a bit to prevent against saturation from fast reconnecting clients kill_thread(cl); cs_writelock(&fakeuser_lock); } } else { client->dup = 1; client->aureader_list = NULL; cs_strncpy(buf, cs_inet_ntoa(ip), sizeof(buf)); cs_log("client(%8lX) duplicate user '%s' from %s (current %s) set to fake (uniq=%d)", (unsigned long)pthread_self(), usr, cs_inet_ntoa(cl->ip), buf, uniq); if (client->failban & BAN_DUPLICATE) { cs_add_violation_by_ip(ip, get_module(client)->ptab->ports[client->port_idx].s_port, usr); } if (cfg.dropdups) { cs_writeunlock(&fakeuser_lock); // we need to unlock here as cs_disconnect_client kills the current thread! cs_sleepms(100); // sleep a bit to prevent against saturation from fast reconnecting clients cs_disconnect_client(client); cs_writelock(&fakeuser_lock); } break; } } } cs_writeunlock(&fakeuser_lock); }
static int32_t monitor_recv(struct s_client * client, uchar *buf, int32_t l) { int32_t n; uchar nbuf[3] = { 'U', 0, 0 }; static int32_t bpos=0, res = 0; static uchar *bbuf=NULL; if (!bbuf) { if (!cs_malloc(&bbuf, l)) return 0; } if (bpos) memcpy(buf, bbuf, n=bpos); else n=recv_from_udpipe(buf); bpos=0; if (!n) return buf[0]=0; if (buf[0]=='&') { int32_t bsize; if (n<21) // 5+16 is minimum { cs_log("packet too small!"); return buf[0]=0; } res = secmon_auth_client(buf+1); if (res == -1) { cs_disconnect_client(client); return 0; } if (!res) return buf[0]=0; aes_decrypt(client, buf+5, 16); bsize=boundary(4, buf[9]+5)+5; // cs_log("n=%d bsize=%d", n, bsize); if (n>bsize) { // cs_log("DO >>>> copy-back"); memcpy(bbuf, buf+bsize, bpos=n-bsize); n=bsize; uchar *nbuf_cpy; if (cs_malloc(&nbuf_cpy, sizeof(nbuf))) { memcpy(nbuf_cpy, nbuf, sizeof(nbuf)); add_job(client, ACTION_CLIENT_UDP, &nbuf_cpy, sizeof(nbuf)); } } else if (n<bsize) { cs_log("packet-size mismatch !"); return buf[0]=0; } aes_decrypt(client, buf+21, n-21); uchar tmp[10]; if (memcmp(buf+5, i2b_buf(4, crc32(0L, buf+10, n-10), tmp), 4)) { cs_log("CRC error ! wrong password ?"); return buf[0]=0; } n=buf[9]; memmove(buf, buf+10, n); } else { uchar *p; if (monitor_check_ip() == -1) { cs_disconnect_client(client); return 0; } buf[n]='\0'; if ((p=(uchar *)strchr((char *)buf, 10)) && (bpos=n-(p-buf)-1)) { memcpy(bbuf, p+1, bpos); n=p-buf; uchar *nbuf_cpy; if (cs_malloc(&nbuf_cpy, sizeof(nbuf))) { memcpy(nbuf_cpy, nbuf, sizeof(nbuf)); add_job(client, ACTION_CLIENT_UDP, &nbuf_cpy, sizeof(nbuf)); } } } buf[n]='\0'; n=strlen(trim((char *)buf)); if (n) client->last=time((time_t *) 0); return n; }