void rcv_chat_invite (struct htlc_conn *htlc) { struct htlc_conn *htlcp; u_int32_t uid = 0, ref = 0; u_int16_t uid16; dh_start(htlc) switch (dh_type) { case HTLC_DATA_UID: dh_getint(uid); break; case HTLC_DATA_CHAT_ID: dh_getint(ref); break; } dh_end() if (ref && uid) { if ((htlcp = isclient(htlc->sid, uid))) { struct htlc_chat *chat = chat_lookup_ref(ref); if (!chat || !chat_isset(htlc, chat, 0)) { send_taskerror(htlc, "who?!?"); return; } if (chat_isset(htlcp, chat, 0)) { char buf[64]; u_int16_t len; len = snprintf(buf, sizeof(buf), "%s is already in chat 0x%x", htlcp->name, chat->ref); if (len == (u_int16_t)-1) len = sizeof(buf); send_taskerror(htlc, buf); return; } chat_set(htlcp, chat, 1); hlwrite(htlc, HTLS_HDR_TASK, 0, 0); ref = htonl(ref); uid16 = htons(htlc->uid); hlwrite(htlcp, HTLS_HDR_CHAT_INVITE, 0, 3, HTLS_DATA_CHAT_ID, sizeof(ref), &ref, HTLS_DATA_UID, sizeof(uid16), &uid16, HTLS_DATA_NAME, strlen(htlc->name), htlc->name); } else send_taskerror(htlc, "who?!?"); } else send_taskerror(htlc, "huh?!?"); }
void rcv_chat_part (struct htlc_conn *htlc) { u_int32_t ref = 0; struct htlc_chat *chat; dh_start(htlc) if (dh_type != HTLC_DATA_CHAT_ID) continue; dh_getint(ref); if ((chat = chat_lookup_ref(ref)) && chat_isset(htlc, chat, 0)) { chat_clr(htlc, chat, 0); if (!chat->nusers) chat_delete(chat); else { struct htlc_conn *htlcp; u_int16_t uid; ref = htonl(ref); uid = htons(htlc->uid); for (htlcp = htlc_list->next; htlcp; htlcp = htlcp->next) if (chat_isset(htlcp, chat, 0)) hlwrite(htlcp, HTLS_HDR_CHAT_USER_PART, 0, 2, HTLS_DATA_CHAT_ID, sizeof(ref), &ref, HTLS_DATA_UID, sizeof(uid), &uid); } } dh_end() }
void rcv_chat_create (struct htlc_conn *htlc) { struct htlc_conn *htlcp; u_int32_t uid = 0, ref; u_int16_t uid16, icon, color; dh_start(htlc) if (dh_type != HTLC_DATA_UID) continue; dh_getint(uid); if ((htlcp = isclient(htlc->sid, uid))) { struct htlc_chat *chat = chat_new(); chat_set(htlc, chat, 0); ref = htonl(chat->ref); uid16 = htons(htlc->uid); icon = htons(htlc->icon); color = htons(htlc->color); hlwrite(htlc, HTLS_HDR_TASK, 0, 5, HTLS_DATA_CHAT_ID, sizeof(ref), &ref, HTLS_DATA_UID, sizeof(uid16), &uid16, HTLS_DATA_ICON, sizeof(icon), &icon, HTLS_DATA_COLOUR, sizeof(color), &color, HTLS_DATA_NAME, strlen(htlc->name), htlc->name); if (htlc->uid != (u_int16_t)uid) hlwrite(htlcp, HTLS_HDR_CHAT_INVITE, 0, 3, HTLS_DATA_CHAT_ID, sizeof(ref), &ref, HTLS_DATA_UID, sizeof(uid16), &uid16, HTLS_DATA_NAME, strlen(htlc->name), htlc->name); } else send_taskerror(htlc, "who?!?"); dh_end() }
void rcv_folder_put (struct htlc_conn *htlc) { u_int16_t fnlen = 0, resume = 0; char path[MAXPATHLEN], dir[MAXPATHLEN], filename[NAME_MAX]; char abuf[HOSTLEN+1], buf[128]; struct stat sb; int err, siz, len; u_int32_t ref, data_pos = 0, rsrc_pos = 0, totalsize = 0, nfiles = 0; u_int8_t rflt[74]; struct SOCKADDR_IN lsaddr; struct htxf_conn *htxf; u_int16_t i; if (htlc->nr_puts >= htlc->put_limit) { len = snprintf(buf, sizeof(buf), "%u at a time", htlc->put_limit); hlwrite(htlc, HTLS_HDR_TASK, 1, 1, HTLS_DATA_TASKERROR, len, buf); return; } if (nr_puts >= hxd_cfg.limits.total_uploads) { len = snprintf(buf, sizeof(buf), "maximum number of total uploads reached (%u >= %d)", nr_gets, hxd_cfg.limits.total_uploads); hlwrite(htlc, HTLS_HDR_TASK, 1, 1, HTLS_DATA_TASKERROR, len, buf); return; } for (i = 0; i < HTXF_PUT_MAX; i++) if (!htlc->htxf_in[i]) break; if (i == HTXF_PUT_MAX) { snd_strerror(htlc, EAGAIN); return; } dh_start(htlc) switch (dh_type) { case HTLC_DATA_FILE_NAME: fnlen = dh_len >= NAME_MAX ? NAME_MAX - 1 : dh_len; read_filename(filename, dh_data, fnlen); break; case HTLC_DATA_DIR: if ((err = hldir_to_path(dh, ROOTDIR, dir, dir))) { snd_strerror(htlc, err); return; } break; case HTLC_DATA_FILE_PREVIEW: dh_getint(resume); break; case HTLC_DATA_HTXF_SIZE: dh_getint(totalsize); break; case HTLC_DATA_FILE_NFILES: dh_getint(nfiles); break; } dh_end() if (!htlc->access.upload_anywhere && (!dir[0] || (!strcasestr(dir, "UPLOAD") && !strcasestr(dir, "DROP BOX")))) { snd_strerror(htlc, EPERM); return; } if (!fnlen && !dir[0]) { /* No file name given */ hlwrite(htlc, HTLS_HDR_TASK, 1, 1, HTLS_DATA_TASKERROR, 6, "huh?!?"); return; } if (dir[0]) { if (fnlen) snprintf(path, sizeof(path), "%s/%s", dir, filename); else strcpy(path, dir); } else { snprintf(path, sizeof(path), "%s/%s", ROOTDIR, filename); } #ifdef HAVE_CORESERVICES resolve_alias_path(path, path); #endif if (!resume) { if (!stat(path, &sb)) { snd_strerror(htlc, EEXIST); return; } if (errno != ENOENT) { snd_strerror(htlc, errno); return; } SYS_mkdir(path, hxd_cfg.permissions.directories); } else { if (stat(path, &sb)) { snd_strerror(htlc, errno); return; } if (!S_ISDIR(sb.st_mode)) { snd_strerror(htlc, ENOTDIR); return; } } ref = htxf_ref_new(htlc); ref = htonl(ref); siz = sizeof(struct SOCKADDR_IN); if (getsockname(htlc->fd, (struct sockaddr *)&lsaddr, &siz)) { hxd_log("rcv_file_get: getsockname: %s", strerror(errno)); snd_strerror(htlc, errno); return; } htxf = htxf_new(htlc, 1); htxf->type = HTXF_TYPE_FOLDER; htxf->data_pos = data_pos; htxf->rsrc_pos = rsrc_pos; htxf->total_size = totalsize; htxf->ref = ref; htxf->sockaddr = htlc->sockaddr; htxf->listen_sockaddr = lsaddr; htxf->listen_sockaddr.SIN_PORT = htons(ntohs(htxf->listen_sockaddr.SIN_PORT) + 1); strcpy(htxf->path, path); htlc->nr_puts++; nr_puts++; if (log_upload) { inaddr2str(abuf, &htlc->sockaddr); hxd_log("%s@%s:%u - %s:%u:%u:%s - upload %s:%08x", htlc->userid, abuf, ntohs(htlc->sockaddr.SIN_PORT), htlc->name, htlc->icon, htlc->uid, htlc->login, htxf->path, htxf->ref); } if (!resume) hlwrite(htlc, HTLS_HDR_TASK, 0, 1, HTLS_DATA_HTXF_REF, sizeof(ref), &ref); else hlwrite(htlc, HTLS_HDR_TASK, 0, 2, HTLS_DATA_RFLT, 74, rflt, HTLS_DATA_HTXF_REF, sizeof(ref), &ref); }
void rcv_folder_get (struct htlc_conn *htlc) { u_int16_t fnlen = 0, preview = 0; char path[MAXPATHLEN], dir[MAXPATHLEN], filename[NAME_MAX], pathbuf[MAXPATHLEN]; char abuf[HOSTLEN+1], buf[128]; struct stat sb; u_int32_t size = 0, data_size = 0, rsrc_size = 0, ref, data_pos = 0, rsrc_pos = 0, nfiles = 0; int err, siz, len; struct SOCKADDR_IN lsaddr; struct htxf_conn *htxf; u_int16_t i; DIR *dirp; struct dirent *de; dir[0] = 0; if (htlc->nr_gets >= htlc->get_limit) { len = snprintf(buf, sizeof(buf), "%u at a time", htlc->get_limit); hlwrite(htlc, HTLS_HDR_TASK, 1, 1, HTLS_DATA_TASKERROR, len, buf); return; } if (nr_gets >= hxd_cfg.limits.total_downloads) { len = snprintf(buf, sizeof(buf), "maximum number of total downloads reached (%u >= %d)", nr_gets, hxd_cfg.limits.total_downloads); hlwrite(htlc, HTLS_HDR_TASK, 1, 1, HTLS_DATA_TASKERROR, len, buf); return; } for (i = 0; i < HTXF_GET_MAX; i++) if (!htlc->htxf_out[i]) break; if (i == HTXF_GET_MAX) { snd_strerror(htlc, EAGAIN); return; } dh_start(htlc) switch (dh_type) { case HTLC_DATA_FILE_NAME: fnlen = dh_len >= NAME_MAX ? NAME_MAX - 1 : dh_len; read_filename(filename, dh_data, fnlen); break; case HTLC_DATA_DIR: if ((err = hldir_to_path(dh, ROOTDIR, dir, dir))) { snd_strerror(htlc, err); return; } break; case HTLC_DATA_RFLT: if (dh_len >= 50) L32NTOH(data_pos, &dh_data[46]); if (dh_len >= 66) L32NTOH(rsrc_pos, &dh_data[62]); break; case HTLC_DATA_FILE_PREVIEW: dh_getint(preview); break; } dh_end() if (!fnlen && !dir[0]) { /* No file name given */ hlwrite(htlc, HTLS_HDR_TASK, 1, 1, HTLS_DATA_TASKERROR, 6, "huh?!?"); return; } if (dir[0]) { if (fnlen) snprintf(path, sizeof(path), "%s/%s", dir, filename); else strcpy(path, dir); } else { snprintf(path, sizeof(path), "%s/%s", ROOTDIR, filename); } #ifdef HAVE_CORESERVICES resolve_alias_path(path, path); #endif if (check_dropbox(htlc, path)) { snd_strerror(htlc, EPERM); return; } if (stat(path, &sb)) { snd_strerror(htlc, errno); return; } if (!S_ISDIR(sb.st_mode)) { snd_strerror(htlc, ENOTDIR); return; } if (!(dirp = opendir(path))) { snd_strerror(htlc, errno); return; } while ((de = readdir(dirp))) { if (de->d_name[0] == '.') continue; nfiles++; snprintf(pathbuf, sizeof(pathbuf), "%s/%s", path, de->d_name); if (stat(pathbuf, &sb)) continue; if (S_ISDIR(sb.st_mode)) continue; data_size = sb.st_size; rsrc_size = resource_len(pathbuf); size += (data_size - data_pos) + (preview ? 0 : (rsrc_size - rsrc_pos)); size += 133 + ((rsrc_size - rsrc_pos) ? 16 : 0) + comment_len(pathbuf); } closedir(dirp); if (!nfiles) { hlwrite(htlc, HTLS_HDR_TASK, 0, 2, HTLC_DATA_HTXF_SIZE, sizeof(size), &size, HTLC_DATA_FILE_NFILES, sizeof(nfiles), &nfiles); return; } ref = htxf_ref_new(htlc); ref = htonl(ref); siz = sizeof(struct SOCKADDR_IN); if (getsockname(htlc->fd, (struct sockaddr *)&lsaddr, &siz)) { hxd_log("rcv_file_get: getsockname: %s", strerror(errno)); snd_strerror(htlc, errno); return; } htxf = htxf_new(htlc, 0); htxf->type = HTXF_TYPE_FOLDER; htxf->total_size = size; htxf->ref = ref; htxf->preview = preview; htxf->sockaddr = htlc->sockaddr; htxf->listen_sockaddr = lsaddr; htxf->listen_sockaddr.SIN_PORT = htons(ntohs(htxf->listen_sockaddr.SIN_PORT) + 1); strcpy(htxf->path, path); htlc->nr_gets++; nr_gets++; if (log_download) { inaddr2str(abuf, &htlc->sockaddr); hxd_log("%s@%s:%u - %s:%u:%u:%s - download %s:%08x", htlc->userid, abuf, ntohs(htlc->sockaddr.SIN_PORT), htlc->name, htlc->icon, htlc->uid, htlc->login, htxf->path, htxf->ref); } size = htonl(size); nfiles = htonl(nfiles); hlwrite(htlc, HTLS_HDR_TASK, 0, 3, HTLS_DATA_HTXF_SIZE, sizeof(size), &size, HTLS_DATA_FILE_NFILES, sizeof(nfiles), &nfiles, HTLS_DATA_HTXF_REF, sizeof(ref), &ref); }
void rcv_file_get (struct htlc_conn *htlc) { u_int16_t fnlen = 0, preview = 0; char path[MAXPATHLEN], dir[MAXPATHLEN], filename[NAME_MAX]; char abuf[HOSTLEN+1], buf[128]; struct stat sb; u_int32_t size = 0, data_size = 0, rsrc_size = 0, ref, data_pos = 0, rsrc_pos = 0; int err, siz, len; struct SOCKADDR_IN lsaddr; struct htxf_conn *htxf; u_int16_t i; #if defined(CONFIG_HTXF_QUEUE) u_int16_t queue_pos; #endif dir[0] = 0; if (htlc->nr_gets >= htlc->get_limit) { for (i = 0; i < HTXF_GET_MAX; i++) { htxf = htlc->htxf_out[i]; if (!htxf) continue; if ((htxf->total_pos == htxf->total_size) || htxf->gone) goto ok; } len = snprintf(buf, sizeof(buf), "%u at a time", htlc->get_limit); hlwrite(htlc, HTLS_HDR_TASK, 1, 1, HTLS_DATA_TASKERROR, len, buf); return; } ok: #if defined(CONFIG_HTXF_QUEUE) if (!htlc->access_extra.ignore_queue && nr_queued >= hxd_cfg.limits.queue_size) { #else if (nr_gets >= hxd_cfg.limits.total_downloads) { #endif #if defined(CONFIG_HTXF_QUEUE) len = snprintf(buf, sizeof(buf), "queue is full (%u >= %d) please try again later", nr_gets, hxd_cfg.limits.queue_size); #else len = snprintf(buf, sizeof(buf), "maximum number of total downloads reached (%u >= %d)", nr_gets, hxd_cfg.limits.total_downloads); #endif hlwrite(htlc, HTLS_HDR_TASK, 1, 1, HTLS_DATA_TASKERROR, len, buf); return; } for (i = 0; i < HTXF_GET_MAX; i++) if (!htlc->htxf_out[i]) break; if (i == HTXF_GET_MAX) { snd_strerror(htlc, EAGAIN); return; } dh_start(htlc) switch (dh_type) { case HTLC_DATA_FILE_NAME: fnlen = dh_len >= NAME_MAX ? NAME_MAX - 1 : dh_len; read_filename(filename, dh_data, fnlen); break; case HTLC_DATA_DIR: if ((err = hldir_to_path(dh, ROOTDIR, dir, dir))) { snd_strerror(htlc, err); return; } break; case HTLC_DATA_RFLT: if (dh_len >= 50) L32NTOH(data_pos, &dh_data[46]); if (dh_len >= 66) L32NTOH(rsrc_pos, &dh_data[62]); break; case HTLC_DATA_FILE_PREVIEW: dh_getint(preview); break; } dh_end() if (!fnlen && !dir[0]) { /* No file name given */ hlwrite(htlc, HTLS_HDR_TASK, 1, 1, HTLS_DATA_TASKERROR, 6, "huh?!?"); return; } if (dir[0]) { if (fnlen) snprintf(path, sizeof(path), "%s/%s", dir, filename); else strcpy(path, dir); } else { snprintf(path, sizeof(path), "%s/%s", ROOTDIR, filename); } #ifdef HAVE_CORESERVICES resolve_alias_path(path, path); #endif if (check_dropbox(htlc, path)) { snd_strerror(htlc, EPERM); return; } #ifdef CONFIG_HTXF_PREVIEW if (preview) { Image *img, *mimg; ImageInfo ii; ExceptionInfo ei; char previewpath[MAXPATHLEN]; static int magick_inited = 0; if (!magick_inited) { InitializeMagick("hxd"); magick_inited = 1; } #if MaxTextExtent < MAXPATHLEN if (strlen(path) >= sizeof(ii.filename)) { hlwrite(htlc, HTLS_HDR_TASK, 1, 1, HTLS_DATA_TASKERROR, 13, "path too long"); return; } #endif memset(&ii, 0, sizeof(ii)); memset(&ei, 0, sizeof(ei)); GetImageInfo(&ii); GetExceptionInfo(&ei); err = preview_path(previewpath, path, &sb); if (!err) { /* Preview file already exists */ strcpy(ii.filename, previewpath); mimg = ReadImage(&ii, &ei); } else { /* Create preview file */ strcpy(ii.filename, path); img = ReadImage(&ii, &ei); if (!img) goto text_preview; mimg = MinifyImage(img, &ei); DestroyImage(img); } if (!mimg) { hlwrite(htlc, HTLS_HDR_TASK, 1, 1, HTLS_DATA_TASKERROR, 18, "MinifyImage failed"); return; } if (err) { err = preview_path(previewpath, path, 0); if (err) { snd_strerror(htlc, err); DestroyImage(mimg); return; } strcpy(mimg->filename, previewpath); data_pos = 0; rsrc_pos = 0; WriteImage(&ii, mimg); DestroyImage(mimg); } else { DestroyImage(mimg); } strcpy(path, previewpath); } text_preview: #endif if (stat(path, &sb)) { snd_strerror(htlc, errno); return; } if (S_ISDIR(sb.st_mode)) { snd_strerror(htlc, EISDIR); return; } data_size = sb.st_size; size = (data_size - data_pos) + (preview ? 0 : 133); #if defined(CONFIG_HFS) if (hxd_cfg.operation.hfs) { rsrc_size = resource_len(path); size += preview ? 0 : (rsrc_size - rsrc_pos); if (!preview) size += ((rsrc_size - rsrc_pos) ? 16 : 0) + comment_len(path); } #endif ref = htxf_ref_new(htlc); ref = htonl(ref); siz = sizeof(struct SOCKADDR_IN); if (getsockname(htlc->fd, (struct sockaddr *)&lsaddr, &siz)) { hxd_log("rcv_file_get: getsockname: %s", strerror(errno)); snd_strerror(htlc, errno); return; } htxf = htxf_new(htlc, 0); htxf->type = HTXF_TYPE_FILE; htxf->data_size = data_size; htxf->rsrc_size = rsrc_size; htxf->data_pos = data_pos; htxf->rsrc_pos = rsrc_pos; htxf->total_size = size; htxf->ref = ref; htxf->limit_out_Bps = htlc->nr_puts > 0 ? (htlc->limit_uploader_out_Bps ? htlc->limit_uploader_out_Bps : htlc->limit_out_Bps) : htlc->limit_out_Bps; hxd_log("conf: %u!%u", htxf->limit_out_Bps, htlc->limit_out_Bps); htxf->preview = preview; htxf->sockaddr = htlc->sockaddr; htxf->listen_sockaddr = lsaddr; htxf->listen_sockaddr.SIN_PORT = htons(ntohs(htxf->listen_sockaddr.SIN_PORT) + 1); strcpy(htxf->path, path); htlc->nr_gets++; nr_gets++; #if defined(CONFIG_HTXF_QUEUE) if (htlc->access_extra.ignore_queue) htxf->queue_pos = queue_pos = 0; else htxf->queue_pos = queue_pos = insert_into_queue(htlc); #endif if (log_download) { inaddr2str(abuf, &htlc->sockaddr); hxd_log("%s@%s:%u - %s:%u:%u:%s - download %s:%08x", htlc->userid, abuf, ntohs(htlc->sockaddr.SIN_PORT), htlc->name, htlc->icon, htlc->uid, htlc->login, htxf->path, htxf->ref); #if defined(CONFIG_SQL) sql_download(htlc->name, abuf, htlc->login, path); #endif } size = htonl(size); #if defined(CONFIG_HTXF_QUEUE) queue_pos = htons(queue_pos); hlwrite(htlc, HTLS_HDR_TASK, 0, 3, HTLS_DATA_HTXF_REF, sizeof(ref), &ref, HTLS_DATA_HTXF_SIZE, sizeof(size), &size, HTLS_DATA_QUEUE_POSITION, sizeof(queue_pos), &queue_pos); #else hlwrite(htlc, HTLS_HDR_TASK, 0, 2, HTLS_DATA_HTXF_REF, sizeof(ref), &ref, HTLS_DATA_HTXF_SIZE, sizeof(size), &size); #endif } void rcv_file_put (struct htlc_conn *htlc) { u_int16_t fnlen = 0, resume = 0; char path[MAXPATHLEN], dir[MAXPATHLEN], filename[NAME_MAX]; char abuf[HOSTLEN+1], buf[128]; struct stat sb; int err, siz, len; u_int32_t ref, data_pos = 0, rsrc_pos = 0, totalsize = 0; u_int8_t rflt[74]; struct SOCKADDR_IN lsaddr; struct htxf_conn *htxf; u_int16_t i; dir[0] = 0; if (htlc->nr_puts >= htlc->put_limit) { len = snprintf(buf, sizeof(buf), "%u at a time", htlc->put_limit); hlwrite(htlc, HTLS_HDR_TASK, 1, 1, HTLS_DATA_TASKERROR, len, buf); return; } if (nr_puts >= hxd_cfg.limits.total_uploads) { len = snprintf(buf, sizeof(buf), "maximum number of total uploads reached (%u >= %d)", nr_gets, hxd_cfg.limits.total_uploads); hlwrite(htlc, HTLS_HDR_TASK, 1, 1, HTLS_DATA_TASKERROR, len, buf); return; } for (i = 0; i < HTXF_PUT_MAX; i++) if (!htlc->htxf_in[i]) break; if (i == HTXF_PUT_MAX) { snd_strerror(htlc, EAGAIN); return; } dh_start(htlc) switch (dh_type) { case HTLC_DATA_FILE_NAME: fnlen = dh_len >= NAME_MAX ? NAME_MAX - 1 : dh_len; read_filename(filename, dh_data, fnlen); break; case HTLC_DATA_DIR: if ((err = hldir_to_path(dh, ROOTDIR, dir, dir))) { snd_strerror(htlc, err); return; } break; case HTLC_DATA_FILE_PREVIEW: dh_getint(resume); break; case HTLC_DATA_HTXF_SIZE: dh_getint(totalsize); break; } dh_end() if (!htlc->access.upload_anywhere && (!dir[0] || (!strcasestr(dir, "UPLOAD") && !strcasestr(dir, "DROP BOX")))) { snd_strerror(htlc, EPERM); return; } if (!fnlen && !dir[0]) { /* No file name given */ hlwrite(htlc, HTLS_HDR_TASK, 1, 1, HTLS_DATA_TASKERROR, 6, "huh?!?"); return; } if (dir[0]) { if (fnlen) snprintf(path, sizeof(path), "%s/%s", dir, filename); else strcpy(path, dir); } else { snprintf(path, sizeof(path), "%s/%s", ROOTDIR, filename); } #ifdef HAVE_CORESERVICES resolve_alias_path(path, path); #endif if (!resume) { if (!stat(path, &sb)) { snd_strerror(htlc, EEXIST); return; } if (errno != ENOENT) { snd_strerror(htlc, errno); return; } } else { if (stat(path, &sb)) { snd_strerror(htlc, errno); return; } data_pos = sb.st_size; #if defined(CONFIG_HFS) if (hxd_cfg.operation.hfs) rsrc_pos = resource_len(path); #endif memcpy(rflt, "RFLT\0\1\ \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ \0\0\0\2DATA\0\0\0\0\0\0\0\0\0\0\0\0MACR\0\0\0\0\0\0\0\0\0\0\0\0", 74); S32HTON(data_pos, &rflt[46]); S32HTON(rsrc_pos, &rflt[62]); } ref = htxf_ref_new(htlc); ref = htonl(ref); siz = sizeof(struct SOCKADDR_IN); if (getsockname(htlc->fd, (struct sockaddr *)&lsaddr, &siz)) { hxd_log("rcv_file_get: getsockname: %s", strerror(errno)); snd_strerror(htlc, errno); return; } htxf = htxf_new(htlc, 1); htxf->type = HTXF_TYPE_FILE; htxf->data_pos = data_pos; htxf->rsrc_pos = rsrc_pos; htxf->total_size = totalsize; htxf->ref = ref; htxf->sockaddr = htlc->sockaddr; htxf->listen_sockaddr = lsaddr; htxf->listen_sockaddr.SIN_PORT = htons(ntohs(htxf->listen_sockaddr.SIN_PORT) + 1); strcpy(htxf->path, path); htlc->nr_puts++; nr_puts++; if (log_upload) { inaddr2str(abuf, &htlc->sockaddr); hxd_log("%s@%s:%u - %s:%u:%u:%s - upload %s:%08x", htlc->userid, abuf, ntohs(htlc->sockaddr.SIN_PORT), htlc->name, htlc->icon, htlc->uid, htlc->login, htxf->path, htxf->ref); #if defined(CONFIG_SQL) sql_upload(htlc->name, abuf, htlc->login, path); #endif } if (!resume) hlwrite(htlc, HTLS_HDR_TASK, 0, 1, HTLS_DATA_HTXF_REF, sizeof(ref), &ref); else hlwrite(htlc, HTLS_HDR_TASK, 0, 2, HTLS_DATA_RFLT, 74, rflt, HTLS_DATA_HTXF_REF, sizeof(ref), &ref); }
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 }
void rcv_chat_join (struct htlc_conn *htlc) { u_int32_t ref = 0; u_int16_t passlen = 0; u_int16_t uid, icon16, color; u_int8_t *pass = 0; struct htlc_chat *chat; dh_start(htlc) switch (dh_type) { case HTLC_DATA_CHAT_ID: dh_getint(ref); break; case HTLC_DATA_PASSWORD: passlen = dh_len > 31 ? 31 : dh_len; pass = dh_data; break; } dh_end() if (!ref) { send_taskerror(htlc, "huh?!?"); return; } chat = chat_lookup_ref(ref); if (!chat) { send_taskerror(htlc, "who?!?"); return; } if (!chat_isset(htlc, chat, 1)) { if (chat->passwordlen && (passlen != chat->passwordlen || memcmp(chat->password, pass, passlen))) { send_taskerror(htlc, "Uh, no."); return; } } else chat_clr(htlc, chat, 1); chat_set(htlc, chat, 0); { struct qbuf *q = &htlc->out; u_int32_t this_off = q->pos + q->len, pos = this_off + SIZEOF_HL_HDR; u_int32_t len; struct hl_hdr h; struct hl_userlist_hdr uh; u_int16_t nlen; struct htlc_conn *htlcp; struct hl_data_hdr dh; u_int16_t slen; q->len += SIZEOF_HL_HDR; q->buf = xrealloc(q->buf, q->pos + q->len); ref = htonl(ref); uid = htons(htlc->uid); icon16 = htons(htlc->icon); color = htons(htlc->color); for (htlcp = htlc_list->next; htlcp; htlcp = htlcp->next) { if (!chat_isset(htlcp, chat, 0)) continue; if (htlcp != htlc) hlwrite(htlcp, HTLS_HDR_CHAT_USER_CHANGE, 0, 5, HTLS_DATA_CHAT_ID, sizeof(ref), &ref, HTLS_DATA_UID, sizeof(uid), &uid, HTLS_DATA_ICON, sizeof(icon16), &icon16, HTLS_DATA_COLOUR, sizeof(color), &color, HTLS_DATA_NAME, strlen(htlc->name), htlc->name); nlen = strlen(htlcp->name); uh.type = htons(HTLS_DATA_USER_LIST); uh.len = htons(8 + nlen); uh.uid = htons(htlcp->uid); uh.icon = htons(htlcp->icon); uh.color = htons(htlcp->color); uh.nlen = htons(nlen); q->len += SIZEOF_HL_USERLIST_HDR + nlen; q->buf = xrealloc(q->buf, q->pos + q->len); memcpy(&q->buf[pos], &uh, SIZEOF_HL_USERLIST_HDR); pos += SIZEOF_HL_USERLIST_HDR; memcpy(&q->buf[pos], htlcp->name, nlen); pos += nlen; } slen = chat->subjectlen; q->len += SIZEOF_HL_DATA_HDR + slen; q->buf = xrealloc(q->buf, q->pos + q->len); dh.type = htons(HTLS_DATA_CHAT_SUBJECT); dh.len = htons(slen); memcpy(&q->buf[pos], &dh, SIZEOF_HL_DATA_HDR); pos += SIZEOF_HL_DATA_HDR; memcpy(&q->buf[pos], chat->subject, slen); pos += slen; h.type = htonl(HTLS_HDR_TASK); h.trans = htonl(htlc->trans); htlc->trans++; h.flag = 0; len = pos - this_off; h.len = h.len2 = htonl(len - (SIZEOF_HL_HDR - sizeof(h.hc))); h.hc = htons(chat->nusers + 1); memory_copy(q->buf + this_off, &h, SIZEOF_HL_HDR); FD_SET(htlc->fd, &hxd_wfds); #ifdef CONFIG_COMPRESS if (htlc->compress_encode_type != COMPRESS_NONE) len = compress_encode(htlc, this_off, len); #endif #ifdef CONFIG_CIPHER if (htlc->cipher_encode_type != CIPHER_NONE) cipher_encode(htlc, this_off, len); #endif } }