TList *cgm_AddList ( TList *l, int n, void *info ) { int i; if ( l == NULL) return NULL; if ( n < 1) n=1; if ( n > list_n(l) ) return cgm_AppendList( l, info ); --n; /* o usuario ve a lista iniciando em 1 e a */ /* lista e' implementada iniciando em 0 */ if (list_n(l) == list_nba(l)) { list_nba(l) *= 2; list_head(l) = (void **)realloc(list_head(l),list_nba(l)*sizeof(void*)); } for (i=list_n(l)-1; i>=n; --i) list_head(l)[i+1]=list_head(l)[i]; list_head(l)[n]=info; list_n(l)++; return l; }
void *cgm_GetList ( TList *l, int n ) { if ( l == NULL || n <= 0) return NULL; return n > list_n(l) ? NULL : list_head(l)[n-1]; }
TList *cgm_AppendList ( TList *l, void *i ) { if ( l == NULL ) return NULL; if (list_n(l) == list_nba(l)) { list_nba(l) += 32; list_head(l) = (void **)realloc(list_head(l),list_nba(l)*sizeof(void*)); } list_head(l)[list_n(l)]=i; list_n(l)++; return l; }
int cgm_DelEntry ( TList *l, void *entry ) { int i=1; if ( l == NULL || list_n(l) == 0) return 0; for (i=0; i< list_n(l); ++i) if (list_head(l)[i]==entry) { cgm_DelList(l,i+1); /* o usuario ve a lista iniciando em 1 e a */ /* lista e' implementada iniciando em 0 */ return i+1; } return 0; }
void stack_for_each(list *stack, visit_fn visit) { list *p = stack; while (p != NULL) { visit(list_v(p)); p = list_n(p); } }
list* stack_pop(list *stack) { list *obj; assert(stack != NULL); obj = list_n(stack); free(stack); return obj; }
list* stack_push(list *stack, object **v) { list *obj; obj = alloc_stack_node(); list_v(obj) = v; list_n(obj) = stack; return obj; }
void stack_dispose(list *stack) { list *rest; while (stack != NULL) { rest = list_n(stack); free(stack); stack = rest; } }
TList *cgm_NewList ( void ) { TList *l = (TList *) malloc ( sizeof (TList) ); list_nba(l) = 8; list_head(l) = (void **)malloc(list_nba(l)*sizeof(void*)); list_n(l) = 0; return l; }
TList *cgm_DelList ( TList *l, int n ) { int i; if ( l == NULL || list_n(l) == 0 || n < 0) return NULL; if ( n < 1) n=1; if ( n > list_n(l)) n=list_n(l); --n; /* o usuario ve a lista iniciando em 1 e a */ /* lista e' implementada iniciando em 0 */ list_n(l)--; for (i=n; i<list_n(l); ++i) list_head(l)[i]=list_head(l)[i+1]; return l; }
static void rcv_task_login (struct htlc_conn *htlc, void *secure) { char abuf[HOSTLEN+1]; u_int32_t uid; u_int16_t icon16; #ifdef CONFIG_HOPE u_int16_t hc; u_int8_t *p, *mal = 0; u_int16_t mal_len = 0; u_int16_t sklen = 0, macalglen = 0, secure_login = 0, secure_password = 0; u_int8_t password_mac[20]; u_int8_t login[32]; u_int16_t llen, pmaclen; #ifdef CONFIG_CIPHER u_int8_t *s_cipher_al = 0, *c_cipher_al = 0; u_int16_t s_cipher_al_len = 0, c_cipher_al_len = 0; u_int8_t s_cipheralg[32], c_cipheralg[32]; u_int16_t s_cipheralglen = 0, c_cipheralglen = 0; u_int8_t cipheralglist[64]; u_int16_t cipheralglistlen; #endif #ifdef CONFIG_COMPRESS u_int8_t *s_compress_al = 0, *c_compress_al = 0; u_int16_t s_compress_al_len = 0, c_compress_al_len = 0; u_int8_t s_compressalg[32], c_compressalg[32]; u_int16_t s_compressalglen = 0, c_compressalglen = 0; u_int8_t compressalglist[64]; u_int16_t compressalglistlen; #endif if (secure) { dh_start(htlc) switch (dh_type) { case HTLS_DATA_LOGIN: if (dh_len && dh_len == strlen(htlc->macalg) && !memcmp(htlc->macalg, dh_data, dh_len)) secure_login = 1; break; case HTLS_DATA_PASSWORD: if (dh_len && dh_len == strlen(htlc->macalg) && !memcmp(htlc->macalg, dh_data, dh_len)) secure_password = 1; break; case HTLS_DATA_MAC_ALG: mal_len = dh_len; mal = dh_data; break; #ifdef CONFIG_CIPHER case HTLS_DATA_CIPHER_ALG: s_cipher_al_len = dh_len; s_cipher_al = dh_data; break; case HTLC_DATA_CIPHER_ALG: c_cipher_al_len = dh_len; c_cipher_al = dh_data; break; case HTLS_DATA_CIPHER_MODE: break; case HTLC_DATA_CIPHER_MODE: break; case HTLS_DATA_CIPHER_IVEC: break; case HTLC_DATA_CIPHER_IVEC: break; #endif #if defined(CONFIG_COMPRESS) case HTLS_DATA_COMPRESS_ALG: s_compress_al_len = dh_len; s_compress_al = dh_data; break; case HTLC_DATA_COMPRESS_ALG: c_compress_al_len = dh_len; c_compress_al = dh_data; break; #endif case HTLS_DATA_CHECKSUM_ALG: break; case HTLC_DATA_CHECKSUM_ALG: break; case HTLS_DATA_SESSIONKEY: sklen = dh_len > sizeof(htlc->sessionkey) ? sizeof(htlc->sessionkey) : dh_len; memcpy(htlc->sessionkey, dh_data, sklen); htlc->sklen = sklen; break; } dh_end() if (!mal_len) { no_mal: hx_printf_prefix(htlc, 0, INFOPREFIX, "No macalg from server\n"); hx_htlc_close(htlc); memset(htlc->password, 0, sizeof(htlc->password)); return; } p = list_n(mal, mal_len, 0); if (!p || !*p) goto no_mal; macalglen = *p >= sizeof(htlc->macalg) ? sizeof(htlc->macalg)-1 : *p; memcpy(htlc->macalg, p+1, macalglen); htlc->macalg[macalglen] = 0; if (sklen < 32) { hx_printf_prefix(htlc, 0, INFOPREFIX, "sessionkey length (%u) not big enough\n", sklen); hx_htlc_close(htlc); memset(htlc->password, 0, sizeof(htlc->password)); return; } #ifdef CONFIG_IPV6 if (memcmp(htlc->sessionkey, &htlc->sockaddr.SIN_ADDR.S_ADDR, 16) || *((u_int16_t *)(htlc->sessionkey + 16)) != htlc->sockaddr.SIN_PORT) { #else if (*((u_int32_t *)(htlc->sessionkey)) != htlc->sockaddr.SIN_ADDR.S_ADDR || *((u_int16_t *)(htlc->sessionkey + 4)) != htlc->sockaddr.SIN_PORT) { #endif char fakeabuf[HOSTLEN+1], realabuf[HOSTLEN+1]; struct IN_ADDR fakeinaddr; #ifdef CONFIG_IPV6 memcpy(&fakeinaddr.S_ADDR, htlc->sessionkey, 16); inet_ntop(AFINET, (char *)&fakeinaddr, fakeabuf, sizeof(fakeabuf)); inet_ntop(AFINET, (char *)&htlc->sockaddr.SIN_ADDR, realabuf, sizeof(realabuf)); #else fakeinaddr.S_ADDR = *((u_int32_t *)(htlc->sessionkey)); inet_ntoa_r(fakeinaddr, fakeabuf, sizeof(fakeabuf)); inet_ntoa_r(htlc->sockaddr.SIN_ADDR, realabuf, sizeof(realabuf)); #endif hx_printf_prefix(htlc, 0, INFOPREFIX, "Server gave wrong address: %s:%u != %s:%u\n", fakeabuf, ntohs(*((u_int16_t *)(htlc->sessionkey + 4))), realabuf, ntohs(htlc->sockaddr.SIN_PORT)); /* XXX HACK XXX */ if (htlc->secure == 2) { hx_printf_prefix(htlc, 0, INFOPREFIX, "Possible man-in-the-middle attack! Connecting anyway.\n"); } else { hx_printf_prefix(htlc, 0, INFOPREFIX, "Possible man-in-the-middle attack! Closing connection. Use -f to force connect.\n"); hx_htlc_close(htlc); memset(htlc->password, 0, sizeof(htlc->password)); return; } } if (task_inerror(htlc)) { hx_htlc_close(htlc); memset(htlc->password, 0, sizeof(htlc->password)); return; } task_new(htlc, rcv_task_login, 0, 0, "login"); icon16 = htons(htlc->icon); if (secure_login) { llen = hmac_xxx(login, htlc->login, strlen(htlc->login), htlc->sessionkey, sklen, htlc->macalg); if (!llen) { hx_printf_prefix(htlc, 0, INFOPREFIX, "bad HMAC algorithm %s\n", htlc->macalg); hx_htlc_close(htlc); memset(htlc->password, 0, sizeof(htlc->password)); return; } } else { llen = strlen(htlc->login); hl_encode(login, htlc->login, llen); login[llen] = 0; } pmaclen = hmac_xxx(password_mac, htlc->password, strlen(htlc->password), htlc->sessionkey, sklen, htlc->macalg); if (!pmaclen) { hx_printf_prefix(htlc, 0, INFOPREFIX, "bad HMAC algorithm %s\n", htlc->macalg); hx_htlc_close(htlc); return; } hc = 4; #ifdef CONFIG_COMPRESS if (!htlc->compressalg[0] || !strcmp(htlc->compressalg, "NONE")) { hx_printf_prefix(htlc, 0, INFOPREFIX, "WARNING: this connection is not compressed\n"); compressalglistlen = 0; goto no_compress; } if (!c_compress_al_len || !s_compress_al_len) { no_compress_al: hx_printf_prefix(htlc, 0, INFOPREFIX, "No compress algorithm from server\n"); hx_htlc_close(htlc); return; } p = list_n(s_compress_al, s_compress_al_len, 0); if (!p || !*p) goto no_compress_al; s_compressalglen = *p >= sizeof(s_compressalg) ? sizeof(s_compressalg)-1 : *p; memcpy(s_compressalg, p+1, s_compressalglen); s_compressalg[s_compressalglen] = 0; p = list_n(c_compress_al, c_compress_al_len, 0); if (!p || !*p) goto no_compress_al; c_compressalglen = *p >= sizeof(c_compressalg) ? sizeof(c_compressalg)-1 : *p; memcpy(c_compressalg, p+1, c_compressalglen); c_compressalg[c_compressalglen] = 0; if (!valid_compress(c_compressalg)) { hx_printf_prefix(htlc, 0, INFOPREFIX, "Bad client compress algorithm %s\n", c_compressalg); goto ret_badcompress_a; } else if (!valid_compress(s_compressalg)) { hx_printf_prefix(htlc, 0, INFOPREFIX, "Bad server compress algorithm %s\n", s_compressalg); ret_badcompress_a: compressalglistlen = 0; hx_htlc_close(htlc); return; } else { S16HTON(1, compressalglist); compressalglistlen = 2; compressalglist[compressalglistlen] = s_compressalglen; compressalglistlen++; memcpy(compressalglist+compressalglistlen, s_compressalg, s_compressalglen); compressalglistlen += s_compressalglen; } no_compress: hc++; #endif #ifdef CONFIG_CIPHER if (!htlc->cipheralg[0] || !strcmp(htlc->cipheralg, "NONE")) { hx_printf_prefix(htlc, 0, INFOPREFIX, "WARNING: this connection is not encrypted\n"); cipheralglistlen = 0; goto no_cipher; } if (!c_cipher_al_len || !s_cipher_al_len) { no_cal: hx_printf_prefix(htlc, 0, INFOPREFIX, "No cipher algorithm from server\n"); hx_htlc_close(htlc); return; } p = list_n(s_cipher_al, s_cipher_al_len, 0); if (!p || !*p) goto no_cal; s_cipheralglen = *p >= sizeof(s_cipheralg) ? sizeof(s_cipheralg)-1 : *p; memcpy(s_cipheralg, p+1, s_cipheralglen); s_cipheralg[s_cipheralglen] = 0; p = list_n(c_cipher_al, c_cipher_al_len, 0); if (!p || !*p) goto no_cal; c_cipheralglen = *p >= sizeof(c_cipheralg) ? sizeof(c_cipheralg)-1 : *p; memcpy(c_cipheralg, p+1, c_cipheralglen); c_cipheralg[c_cipheralglen] = 0; if (!valid_cipher(c_cipheralg)) { hx_printf_prefix(htlc, 0, INFOPREFIX, "Bad client cipher algorithm %s\n", c_cipheralg); goto ret_badca; } else if (!valid_cipher(s_cipheralg)) { hx_printf_prefix(htlc, 0, INFOPREFIX, "Bad server cipher algorithm %s\n", s_cipheralg); ret_badca: cipheralglistlen = 0; hx_htlc_close(htlc); return; } else { S16HTON(1, cipheralglist); cipheralglistlen = 2; cipheralglist[cipheralglistlen] = s_cipheralglen; cipheralglistlen++; memcpy(cipheralglist+cipheralglistlen, s_cipheralg, s_cipheralglen); cipheralglistlen += s_cipheralglen; } /* server key first */ pmaclen = hmac_xxx(htlc->cipher_decode_key, htlc->password, strlen(htlc->password), password_mac, pmaclen, htlc->macalg); htlc->cipher_decode_keylen = pmaclen; pmaclen = hmac_xxx(htlc->cipher_encode_key, htlc->password, strlen(htlc->password), htlc->cipher_decode_key, pmaclen, htlc->macalg); htlc->cipher_encode_keylen = pmaclen; no_cipher: hc++; #endif memset(htlc->password, 0, sizeof(htlc->password)); hlwrite(htlc, HTLC_HDR_LOGIN, 0, hc, HTLC_DATA_LOGIN, llen, login, HTLC_DATA_PASSWORD, pmaclen, password_mac, #ifdef CONFIG_CIPHER HTLS_DATA_CIPHER_ALG, cipheralglistlen, cipheralglist, #endif #ifdef CONFIG_COMPRESS HTLS_DATA_COMPRESS_ALG, compressalglistlen, compressalglist, #endif HTLC_DATA_NAME, strlen(htlc->name), htlc->name, HTLC_DATA_ICON, 2, &icon16); #ifdef CONFIG_COMPRESS if (compressalglistlen) { hx_printf_prefix(htlc, 0, INFOPREFIX, "compress: server %s client %s\n", c_compressalg, s_compressalg); if (c_compress_al_len) { htlc->compress_encode_type = COMPRESS_GZIP; compress_encode_init(htlc); } if (s_compress_al_len) { htlc->compress_decode_type = COMPRESS_GZIP; compress_decode_init(htlc); } } #endif #ifdef CONFIG_CIPHER if (cipheralglistlen) { hx_printf_prefix(htlc, 0, INFOPREFIX, "cipher: server %s client %s\n", c_cipheralg, s_cipheralg); if (!strcmp(s_cipheralg, "RC4")) htlc->cipher_decode_type = CIPHER_RC4; else if (!strcmp(s_cipheralg, "BLOWFISH")) htlc->cipher_decode_type = CIPHER_BLOWFISH; else if (!strcmp(s_cipheralg, "IDEA")) htlc->cipher_decode_type = CIPHER_IDEA; if (!strcmp(c_cipheralg, "RC4")) htlc->cipher_encode_type = CIPHER_RC4; else if (!strcmp(c_cipheralg, "BLOWFISH")) htlc->cipher_encode_type = CIPHER_BLOWFISH; else if (!strcmp(c_cipheralg, "IDEA")) htlc->cipher_encode_type = CIPHER_IDEA; cipher_encode_init(htlc); cipher_decode_init(htlc); } #endif } else { #endif /* CONFIG_HOPE */ inaddr2str(abuf, &htlc->sockaddr); hx_printf_prefix(htlc, 0, INFOPREFIX, "%s:%u: login %s\n", abuf, ntohs(htlc->sockaddr.SIN_PORT), task_inerror(htlc) ? "failed?" : "successful"); if (!task_inerror(htlc)) { hx_chat_new(htlc, 0); play_sound(snd_login); dh_start(htlc) switch (dh_type) { case HTLS_DATA_UID: dh_getint(uid); htlc->uid = uid; break; case HTLS_DATA_SERVERVERSION: dh_getint(htlc->serverversion); break; case HTLS_DATA_BANNERID: break; case HTLS_DATA_SERVERNAME: hx_printf_prefix(htlc, 0, INFOPREFIX, "servername: %.*s\n", dh_len, dh_data); break; } dh_end() if (htlc->clientversion >= 150 && htlc->serverversion < 150) { icon16 = htons(htlc->icon); hlwrite(htlc, HTLC_HDR_USER_CHANGE, 0, 2, HTLC_DATA_NAME, strlen(htlc->name), htlc->name, HTLC_DATA_ICON, 2, &icon16); } hx_output.on_connect(htlc); } #ifdef CONFIG_HOPE } #endif }