void init_database (const char *host, const char *user, const char *pass, const char *data) { MYSQL *d; last_host = host; last_user = user; last_pass = pass; last_data = data; Db = mysql_init (Db); if (!Db) { hxd_log("mysql_init() failed: %s", mysql_error(Db)); return; } d = mysql_real_connect(Db, host, user, pass, data, 0, 0, 0); if (!d) { hxd_log("mysql_real_connect() failed: %s", mysql_error(Db)); Db = 0; return; } Db = d; }
static RETSIGTYPE sig_hup (int sig __attribute__((__unused__))) { hxd_log("\n"); hxd_log("caught SIGHUP"); timer_add_secs(0, read_config_file, (void *)1); }
static RETSIGTYPE sig_log_info (int sig) { extern const char * const sys_siglist[]; hxd_log("------"); hxd_log("caught signal %d", sig); hxd_log("%s", sys_siglist[sig]); }
void rcv_file_list (struct htlc_conn *htlc) { char rlpath[MAXPATHLEN], path[MAXPATHLEN]; int err; if (htlc->in.pos == SIZEOF_HL_HDR) { hxd_scandir(htlc, ROOTDIR); return; } dh_start(htlc) if (dh_type != HTLC_DATA_DIR) return; if ((err = hldir_to_path(dh, ROOTDIR, rlpath, path))) { snd_strerror(htlc, err); return; } if (check_dropbox(htlc, path)) { /* snd_strerror(htlc, EPERM); */ hlwrite(htlc, HTLS_HDR_TASK, 0, 0); return; } if (log_list) hxd_log("%s:%s:%u - list %s", htlc->name, htlc->login, htlc->uid, path); hxd_scandir(htlc, rlpath); dh_end() }
static int read_config_file (void *ptr) { if (ptr) hxd_log("SIGHUP: rereading config file"); hxd_read_config(hxdconf, &hxd_cfg); umask(hxd_cfg.permissions.umask); #if defined(CONFIG_HOTLINE_SERVER) read_banlist(); read_applevolume(); if (hxd_cfg.operation.hfs) hfs_set_config(hxd_cfg.files.fork, hxd_cfg.permissions.files, hxd_cfg.permissions.directories, hxd_cfg.files.comment, hxd_cfg.files.dir_comment); #ifdef CONFIG_CIPHER cipher_init(); #endif #ifdef CONFIG_NETWORK g_my_sid = hxd_cfg.network.server_id; #endif #endif #if defined(CONFIG_TRACKER_SERVER) tracker_read_banlist(); #endif #ifndef ONLY_TRACKER if (hxd_cfg.operation.trxreg) tracker_register_init(); #endif return 0; }
static void log_backtrace(void) { void *frame_ptrs[64]; int count = backtrace(frame_ptrs, 64); char **fnames = backtrace_symbols(frame_ptrs, count); int i; for (i = 0; i < count; i++) hxd_log("%s", fnames[i]); free(fnames); }
static RETSIGTYPE sig_fatal (int sig) { sig_log_info(sig); #ifdef ENABLE_BACKTRACE hxd_log("Attempting backtrace..."); log_backtrace(); #endif _exit(sig); }
void sql_query (const char *fmt, ...) { va_list ap; char buf[16384]; if (Db) { va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); if (mysql_query(Db, buf) != 0) { // try to re-connect and retry init_database(last_host, last_user, last_pass, last_data); if (mysql_query(Db, buf) != 0) { hxd_log("mysql_query() failed: %s", mysql_error(Db)); hxd_log("mysql_query() query was: %s", buf); } } } }
int tfn (struct timeval *tv) { struct timeval *ctv; time_t s, us, secdiff, usecdiff; hxd_log("timer: %u, %u", tv->tv_sec, tv->tv_usec); if (tv==&tv1)ctv=&ctv1;else if (tv==&tv2)ctv=&ctv2;else if (tv==&tv3)ctv=&ctv3; s = ctv->tv_sec; us = ctv->tv_usec; gettimeofday(ctv,0); secdiff = ctv->tv_sec - s; if (us > ctv->tv_usec) { secdiff--; usecdiff = 1000000 - (us - ctv->tv_usec); } else { usecdiff = ctv->tv_usec - us; } hxd_log("real: %u, %u",secdiff,usecdiff); return 1; }
u_int16_t insert_into_queue (struct htlc_conn *htlc) { if (nr_queued || (nr_gets > hxd_cfg.limits.total_downloads) || (htlc->nr_gets > htlc->get_limit)) { hxd_log("Inserting into queue at #%d. nr_gets=%d, limit=%d, queue limit=%d", nr_queued+1, nr_gets, hxd_cfg.limits.total_downloads, hxd_cfg.limits.queue_size); nr_queued++; return nr_queued; } else { return 0; } }
void rcv_file_mkdir (struct htlc_conn *htlc) { u_int16_t fnlen = 0; char dir[MAXPATHLEN], filename[NAME_MAX], newbuf[MAXPATHLEN]; int err; dir[0] = 0; 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: err = hldir_to_path(dh, ROOTDIR, dir, dir); if (err && err != ENOENT) { snd_strerror(htlc, err); return; } break; } dh_end() if (!fnlen && !dir[0]) { hlwrite(htlc, HTLS_HDR_TASK, 1, 1, HTLS_DATA_TASKERROR, 6, "huh?!?"); return; } if (dir[0]) { if (fnlen) snprintf(newbuf, sizeof(newbuf), "%s/%s", dir, filename); else strcpy(newbuf, dir); } else { snprintf(newbuf, sizeof(newbuf), "%s/%s", ROOTDIR, filename); } if (check_dropbox(htlc, newbuf)) { snd_strerror(htlc, EPERM); return; } if (log_mkdir) hxd_log("%s:%s:%u - mkdir %s", htlc->name, htlc->login, htlc->uid, newbuf); if (SYS_mkdir(newbuf, hxd_cfg.permissions.directories)) snd_strerror(htlc, errno); else hlwrite(htlc, HTLS_HDR_TASK, 0, 0); }
static void loopZ (void) { fd_set rfds, wfds; struct timeval before, tv; gettimeofday(&tv, 0); for (;;) { register int n, i; if (timer_list) { gettimeofday(&before, 0); timer_check(&tv, &before); if (timer_list) tv = timer_list->tv; } rfds = hxd_rfds; wfds = hxd_wfds; n = select(high_fd + 1, &rfds, &wfds, 0, timer_list ? &tv : 0); if (n < 0 && errno != EINTR) { hxd_log("loopZ: select: %s", strerror(errno)); exit(1); } gettimeofday(&tv, 0); if (hxd_cfg.operation.nospam) loopZ_timeval = tv; if (timer_list) { timer_check(&before, &tv); } if (n <= 0) continue; for (i = 0; i < high_fd + 1; i++) { if (FD_ISSET(i, &rfds) && FD_ISSET(i, &hxd_rfds)) { if (hxd_files[i].ready_read) hxd_files[i].ready_read(i); if (!--n) break; } if (FD_ISSET(i, &wfds) && FD_ISSET(i, &hxd_wfds)) { if (hxd_files[i].ready_write) hxd_files[i].ready_write(i); if (!--n) break; } } } }
static inline void fh_sort (struct hl_filelist_hdr **fhdrs, u_int16_t count) { #if WANT_TO_TIME_SORT static int use_qsort = 1; struct timeval start, now; double diff; char secsbuf[32]; if (use_qsort) { gettimeofday(&start, 0); qsort(fhdrs, count, sizeof(struct hl_filelist_hdr *), fh_compare); gettimeofday(&now, 0); } else { u_int16_t i, j; struct hl_filelist_hdr *fhp; gettimeofday(&start, 0); for (i = 0; i < count; i++) for (j = 1; j < count - i; j++) if (fhdrs[j - 1]->fname[0] > fhdrs[j]->fname[0]) { fhp = fhdrs[j - 1]; fhdrs[j - 1] = fhdrs[j]; fhdrs[j] = fhp; } gettimeofday(&now, 0); } diff = (double)(now.tv_sec + now.tv_usec * 0.000001) - (double)(start.tv_sec + start.tv_usec * 0.000001); sprintf(secsbuf, "%g", diff); hxd_log("%ssort %u took %s seconds", use_qsort ? "q" : "bubble ", count, secsbuf); use_qsort = !use_qsort; #else qsort(fhdrs, count, sizeof(struct hl_filelist_hdr *), fh_compare); #endif }
static void account_getdirs (const char *login, char *rootdir, char *newsfile, char *dropbox) { struct stat sb; char dir[MAXPATHLEN]; if (snprintf(dir, MAXPATHLEN, "%s/%s/files", hxd_cfg.paths.accounts, login) == -1) { hxd_log("account_getdirs(%s): path '%s' too long?!?", login, dir); goto default_files; } #ifdef HAVE_CORESERVICES if (!resolve_alias_path(dir, rootdir) || stat(rootdir, &sb)) { #else if (!realpath(dir, rootdir) || stat(rootdir, &sb)) { #endif default_files: #ifdef HAVE_CORESERVICES if (!resolve_alias_path(hxd_cfg.paths.files, rootdir)) { #else if (!realpath(hxd_cfg.paths.files, rootdir)) { #endif hxd_log("could not get realpath of files dir '%s'", hxd_cfg.paths.files); snprintf(rootdir, MAXPATHLEN, "%s", hxd_cfg.paths.files); } } if (snprintf(dir, MAXPATHLEN, "%s/%s/news", hxd_cfg.paths.accounts, login) == -1) { hxd_log("account_getdirs(%s): path '%s' too long?!?", login, dir); goto default_news; } #ifdef HAVE_CORESERVICES if (!resolve_alias_path(dir, newsfile) || stat(newsfile, &sb)) { #else if (!realpath(dir, newsfile) || stat(newsfile, &sb)) { #endif default_news: #ifdef HAVE_CORESERVICES if (!resolve_alias_path(hxd_cfg.paths.news, newsfile)) { #else if (!realpath(hxd_cfg.paths.news, newsfile)) { #endif hxd_log("could not get realpath of news file '%s'", hxd_cfg.paths.news); snprintf(newsfile, MAXPATHLEN, "%s", hxd_cfg.paths.news); } } if (snprintf(dir, MAXPATHLEN, "%s/%s/dropbox", hxd_cfg.paths.accounts, login) == -1) { hxd_log("account_getdirs(%s): path '%s' too long?!?", login, dir); goto default_dropbox; } #ifdef HAVE_CORESERVICES if (!resolve_alias_path(dir, dropbox) || stat(dropbox, &sb)) { #else if (!realpath(dir, dropbox) || stat(dropbox, &sb)) { #endif default_dropbox: dropbox[0] = 0; } } void account_getconf (struct htlc_conn *htlc) { struct hxd_config cfg; char file[MAXPATHLEN]; account_getdirs(htlc->login, htlc->rootdir, htlc->newsfile, htlc->dropbox); if (snprintf(file, MAXPATHLEN, "%s/%s/conf", hxd_cfg.paths.accounts, htlc->login) == -1) { hxd_log("account_getconf(%s): path '%s' too long?!?", htlc->login, file); return; } memset(&cfg, 0, sizeof(cfg)); cfg.limits.individual_exec = hxd_cfg.limits.individual_exec; cfg.limits.individual_downloads = hxd_cfg.limits.individual_downloads; cfg.limits.individual_uploads = hxd_cfg.limits.individual_uploads; cfg.limits.out_Bps = hxd_cfg.limits.out_Bps; /* remote server queueing spec */ cfg.limits.can_omit_queue = hxd_cfg.limits.can_omit_queue; hxd_read_config(file, &cfg); htlc->get_limit = cfg.limits.individual_downloads > HTXF_GET_MAX ? HTXF_GET_MAX : cfg.limits.individual_downloads; htlc->put_limit = cfg.limits.individual_uploads > HTXF_PUT_MAX ? HTXF_PUT_MAX : cfg.limits.individual_uploads; htlc->limit_out_Bps = cfg.limits.out_Bps; htlc->exec_limit = cfg.limits.individual_exec; /* remote server queuing spec */ htlc->can_download = cfg.limits.can_omit_queue; } int access_extra_set (struct extra_access_bits *acc, char *p, int val) { switch (p[0]) { case 'a': if (!strcmp(p, "access_volatile")) { acc->access_volatile = val; return 0; } case 'c': if (!strcmp(p, "can_spam")) { acc->can_spam = val; return 0; } else if (!strcmp(p, "chat_private")) { acc->chat_private = val; return 0; } case 'd': if (!strcmp(p, "debug")) { acc->debug = val; return 0; } case 'f': if (!strcmp(p, "file_getinfo")) { acc->file_getinfo = val; return 0; } else if (!strcmp(p, "file_hash")) { acc->file_hash = val; return 0; } else if (!strcmp(p, "file_list")) { acc->file_list = val; return 0; } case 'i': if (!strcmp(p, "is_0wn3d")) { acc->is_0wn3d = val; return 0; } else if (!strcmp(p, "info_get_address")) { acc->info_get_address = val; return 0; } else if (!strcmp(p, "info_get_login")) { acc->info_get_login = val; return 0; } case 'm': if (!strcmp(p, "manage_users")) { acc->manage_users = val; return 0; } else if (!strcmp(p, "msg")) { acc->msg = val; return 0; } case 's': if (!strcmp(p, "set_subject")) { acc->set_subject = val; return 0; } case 'u': if (!strcmp(p, "user_0wn")) { acc->user_0wn = val; return 0; } else if (!strcmp(p, "user_access")) { acc->user_access = val; return 0; } else if (!strcmp(p, "user_color")) { acc->user_color = val; return 0; } else if (!strcmp(p, "user_getlist")) { acc->user_getlist = val; return 0; } else if (!strcmp(p, "user_visibility")) { acc->user_visibility = val; return 0; } } return 1; } void access_extra_set_default (struct login_defaults *def, char *p, u_int16_t val) { if (!strcmp(p, "color")) { def->color = val; def->has_default_color = 1; } else if (!strcmp(p, "icon")) { def->icon = val; def->has_default_icon = 1; } } int set_access_bit (struct hl_access_bits *acc, char *p, int val) { switch (p[0]) { case 'c': if (!strcmp(p, "cant_be_disconnected")) { acc->cant_be_disconnected = val; return 0; } else if (!strcmp(p, "comment_files")) { acc->comment_files = val; return 0; } else if (!strcmp(p, "comment_folders")) { acc->comment_folders = val; return 0; } else if (!strcmp(p, "create_folders")) { acc->create_folders = val; return 0; } else if (!strcmp(p, "create_users")) { acc->create_users = val; return 0; } case 'd': if (!strcmp(p, "delete_files")) { acc->delete_files = val; return 0; } else if (!strcmp(p, "delete_folders")) { acc->delete_folders = val; return 0; } else if (!strcmp(p, "delete_users")) { acc->delete_users = val; return 0; } else if (!strcmp(p, "disconnect_users")) { acc->disconnect_users = val; return 0; } else if (!strcmp(p, "dont_show_agreement")) { acc->dont_show_agreement = val; return 0; } else if (!strcmp(p, "download_files")) { acc->download_files = val; return 0; } else if (!strcmp(p, "download_folders")) { acc->download_folders = val; return 0; } case 'g': if (!strcmp(p, "get_user_info")) { acc->get_user_info = val; return 0; } case 'm': if (!strcmp(p, "make_aliases")) { acc->make_aliases = val; return 0; } else if (!strcmp(p, "modify_users")) { acc->modify_users = val; return 0; } else if (!strcmp(p, "move_files")) { acc->move_files = val; return 0; } else if (!strcmp(p, "move_folders")) { acc->move_folders = val; return 0; } case 'p': if (!strcmp(p, "post_news")) { acc->post_news = val; return 0; } case 'r': if (!strcmp(p, "read_chat")) { acc->read_chat = val; return 0; } else if (!strcmp(p, "read_news")) { acc->read_news = val; return 0; } else if (!strcmp(p, "read_users")) { acc->read_users = val; return 0; } else if (!strcmp(p, "rename_files")) { acc->rename_files = val; return 0; } else if (!strcmp(p, "rename_folders")) { acc->rename_folders = val; return 0; } case 's': if (!strcmp(p, "send_chat")) { acc->send_chat = val; return 0; } case 'u': if (!strcmp(p, "upload_anywhere")) { acc->upload_anywhere = val; return 0; } else if (!strcmp(p, "upload_files")) { acc->upload_files = val; return 0; } else if (!strcmp(p, "use_any_name")) { acc->use_any_name = val; return 0; } case 'v': if (!strcmp(p, "view_drop_boxes")) { acc->view_drop_boxes = val; return 0; } } return 1; } void account_get_access_extra (struct htlc_conn *htlc) { int fd, r, lastlinelen, val; u_int16_t def_val; char buf[1024], *p, *lastlinep, *nextp, *ep; char path[MAXPATHLEN]; /* set the default options before reading in real values */ htlc->access_extra.chat_private = 1; htlc->access_extra.msg = 1; htlc->access_extra.user_getlist = 1; htlc->access_extra.file_list = 1; htlc->access_extra.file_getinfo = 1; htlc->access_extra.file_hash = 1; htlc->access_extra.user_visibility = 0; htlc->access_extra.user_color = 0; htlc->access_extra.set_subject = 0; htlc->access_extra.debug = 0; htlc->access_extra.user_access = 0; htlc->access_extra.access_volatile = 1; htlc->access_extra.user_0wn = 0; htlc->access_extra.is_0wn3d = 1; htlc->access_extra.manage_users = 0; htlc->access_extra.info_get_address = 1; htlc->access_extra.info_get_login = 1; /* the below is used to track if the color/icon has been set in the access * file (better than just testing if it is non-zero) */ htlc->defaults.has_default_color = 0; /* reserved for internal use */ htlc->defaults.has_default_icon = 0; /* reserved for internal use */ if (snprintf(path, MAXPATHLEN, "%s/%s/access", hxd_cfg.paths.accounts, htlc->login) == -1) { hxd_log("account_getconf(%s): path '%s' too long?!?", htlc->login, path); return; } if ((fd = open(path, O_RDONLY)) < 0) return; p = lastlinep = buf; for (;;) { lastlinelen = p - lastlinep; if (lastlinelen) { memcpy(buf, lastlinep, lastlinelen); if (sizeof(buf)-lastlinelen-1 == 0) break; } r = read(fd, buf+lastlinelen, sizeof(buf)-lastlinelen-1); if (r <= 0) break; buf[r] = 0; for (p = buf; *p; p = nextp) { nextp = strchr(p, '\n'); if (nextp) { *nextp = 0; nextp++; lastlinep = nextp; } else { do p++; while (*p); break; } while (isspace(*p)) p++; if (*p == '#') continue; for (ep = p; *ep; ep++) { if (*ep == '=' || isspace(*ep)) { if (*ep == '=') { *ep++ = 0; goto is_eq; } *ep++ = 0; while (isspace(*ep)) ep++; if (*ep != '=') break; else *ep++ = 0; is_eq: while (isspace(*ep)) ep++; if (!*ep) break; val = *ep == '1' ? 1 : 0; access_extra_set(&htlc->access_extra, p, val); def_val = strtoul(ep, 0, 0); access_extra_set_default(&htlc->defaults, p, def_val); } } } } close(fd); } int account_read (const char *login, char *password, char *name, struct hl_access_bits *acc) { struct hl_user_data user_data; int fd, r; u_int16_t len; char path[MAXPATHLEN]; if (strchr(login, DIRCHAR)) return EPERM; if (snprintf(path, sizeof(path), "%s/%s/UserData", hxd_cfg.paths.accounts, login) == -1) { hxd_log("account_read(%s): path '%s' too long?!?", login, path); return ENAMETOOLONG; } fd = open(path, O_RDONLY); if (fd < 0) { hxd_log("account_read(%s): open(%s): %s", login, path, strerror(errno)); return errno; } if ((r = read(fd, &user_data, 734)) != 734) { hxd_log("account_read(%s): read(%d, %x, %u) == %d: %s", login, fd, &user_data, 734, r, strerror(errno)); close(fd); return errno; } close(fd); if (acc) *acc = user_data.access; if (name) { len = ntohs(user_data.nlen) > 31 ? 31 : ntohs(user_data.nlen); memcpy(name, user_data.name, len); name[len] = 0; } if (password) { len = ntohs(user_data.plen) > 31 ? 31 : ntohs(user_data.plen); hl_decode(password, user_data.password, len); password[len] = 0; } memset(&user_data, 0, sizeof(user_data)); return 0; } int account_write (const char *login, const char *password, const char *name, const struct hl_access_bits *acc) { int fd, r, err; char path[MAXPATHLEN]; struct hl_user_data user_data; u_int16_t nlen, llen, plen; struct stat sb; if (strchr(login, '/')) return EPERM; if (snprintf(path, sizeof(path), "%s/%s", hxd_cfg.paths.accounts, login) == -1) { hxd_log("account_write(%s): path '%s' too long?!?", login, path); return ENAMETOOLONG; } if (stat(path, &sb)) { if (mkdir(path, hxd_cfg.permissions.account_directories)) { hxd_log("account_write(%s): mkdir(%s): %s", login, path, strerror(errno)); return errno; } } if (snprintf(path, sizeof(path), "%s/%s/UserData", hxd_cfg.paths.accounts, login) == -1) { hxd_log("account_write(%s): path '%s' too long?!?", login, path); return ENAMETOOLONG; } fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, hxd_cfg.permissions.account_files); if (fd < 0) { hxd_log("account_write(%s): open(%s) %s", login, path, strerror(errno)); return errno; } if ((nlen = strlen(name)) > 134) nlen = 134; if ((llen = strlen(login)) > 34) llen = 34; if ((plen = strlen(password)) > 32) plen = 32; memset(&user_data, 0, sizeof(user_data)); user_data.magic = htonl(0x00010000); user_data.access = *acc; user_data.nlen = htons(nlen); memcpy(user_data.name, name, nlen); user_data.llen = htons(llen); memcpy(user_data.login, login, llen); user_data.plen = htons(plen); hl_encode(user_data.password, password, plen); err = 0; if ((r = write(fd, &user_data, 734)) != 734) { err = errno; hxd_log("account_write(%s): write(%d, %x, %u) == %d: %s", login, fd, &user_data, 734, r, strerror(err)); } else { fsync(fd); } close(fd); memset(&user_data, 0, sizeof(user_data)); return err; } int account_delete (const char *login) { char path[MAXPATHLEN]; /* check if the account name has a '/' in it */ if (strchr(login, '/')) return EPERM; if (snprintf(path, sizeof(path), "%s/%s/UserData", hxd_cfg.paths.accounts, login) == -1) { hxd_log("account_delete: %s: path '%s' too long?!?", login, path); return ENAMETOOLONG; } if (unlink(path)) { hxd_log("account_delete: %s: unlink(%s): %s", login, path, strerror(errno)); return errno; } return 0; }
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 create_account (struct htlc_conn *htlc, int create) { struct htlc_conn *htlcp; struct hl_access_bits acc; u_int8_t name[32], login[32], password[32]; u_int16_t nlen = 0, llen = 0, plen = 0, alen = 0; int err; name[0] = password[0] = 0; memset(&acc, 0, sizeof(struct hl_access_bits)); dh_start(htlc) switch (dh_type) { case HTLC_DATA_NAME: nlen = dh_len > 31 ? 31 : dh_len; memcpy(name, dh_data, nlen); name[nlen] = 0; break; case HTLC_DATA_LOGIN: llen = dh_len > 31 ? 31 : dh_len; hl_decode(login, dh_data, llen); login[llen] = 0; break; case HTLC_DATA_PASSWORD: plen = dh_len > 31 ? 31 : dh_len; hl_decode(password, dh_data, plen); password[plen] = 0; break; case HTLC_DATA_ACCESS: alen = dh_len; if (alen >= sizeof(struct hl_access_bits)) memcpy(&acc, dh_data, sizeof(struct hl_access_bits)); break; } dh_end() /* issue an error if the client didn't provide a login name */ if (!llen) { send_taskerror(htlc, "huh?!?"); return; } hxd_log("%s:%s:%u - create/modify account %s", htlc->name, htlc->login, htlc->uid, login); if ((plen == 1 && password[0] == 255)) account_read(login, password, 0, 0); if (!nlen) account_read(login, 0, name, 0); if (!alen) account_read(login, 0, 0, &acc); if ((err = account_write(login, password, name, &acc))) { snd_strerror(htlc, err); return; } memset(password, 0, sizeof(password)); /* confirm that account was created/modified successfully */ hlwrite(htlc, HTLS_HDR_TASK, 0, 0); /* update the users using this account with new priveleges */ for (htlcp = htlc_list->next; htlcp; htlcp = htlcp->next) { /* check if user is logged in with the account */ if (!strcmp(login, htlcp->login)) { /* update name of the account (might have changed) */ strcpy(htlcp->defaults.name, name); /* support for rfc2 on 256 indexed color, only update the user's * color if they are using index 0 or 1 color, standard protocol */ if (htlcp->color == 0 || htlcp->color == 2) htlcp->color = acc.disconnect_users ? 2 : 0; else if (htlcp->color == 1 || htlcp->color == 3) htlcp->color = acc.disconnect_users ? 3 : 1; /* send the updated access priveleges to the user */ memcpy(&htlcp->access, &acc, sizeof(struct hl_access_bits)); update_access(htlcp); /* send the updated user information to the clients */ update_user(htlcp); } } /* for */ if (create && strlen(hxd_cfg.paths.nuser)) { /* execute a script after adding the account */ switch (fork()) { case -1: hxd_log("create_account: fork: %s", strerror(errno)); break; case 0: { char *envp[3], acctdir[MAXPATHLEN + 16], account[32]; char rlpath[MAXPATHLEN], expath[MAXPATHLEN]; #ifdef HAVE_CORESERVICES resolve_alias_path(hxd_cfg.paths.nuser, expath); resolve_alias_path(hxd_cfg.paths.accounts, rlpath); #else realpath(hxd_cfg.paths.nuser, expath); realpath(hxd_cfg.paths.accounts, rlpath); #endif snprintf(acctdir, sizeof(acctdir), "ACCOUNTDIR=%s", rlpath); snprintf(account, sizeof(htlc->login), "ACCOUNT=%s", login); envp[0] = acctdir; envp[1] = account; envp[2] = 0; execle(expath, expath, 0, envp); exit(0); } } } }
int account_trusted (const char *login, const char *userid, const char *address) { char path[MAXPATHLEN], buf[1024], *p, *nextp, *ap, *up, *lastlinep; int fd, r, lastlinelen; if (snprintf(path, sizeof(path), "%s/%s/allow", hxd_cfg.paths.accounts, login) == -1) { hxd_log("account_trusted(%s): path '%s' too long?!?", login, path); return 1; } if ((fd = open(path, O_RDONLY)) < 0) goto deny; p = lastlinep = buf; for (;;) { lastlinelen = p - lastlinep; if (lastlinelen) { memcpy(buf, lastlinep, lastlinelen); if (sizeof(buf)-lastlinelen-1 == 0) break; } r = read(fd, buf+lastlinelen, sizeof(buf)-lastlinelen-1); if (r <= 0) break; buf[r] = 0; for (p = buf; *p; p = nextp) { nextp = strchr(p, '\n'); if (nextp) { *nextp = 0; nextp++; lastlinep = nextp; } else { do p++; while (*p); break; } if (*p == '#') continue; for (ap = p; *ap; ap++) if (*ap == '@') { up = p; *ap++ = 0; goto allow_match; } ap = p; up = 0; allow_match: if (!fnmatch(ap, address, FNM_NOESCAPE) && (!up || !fnmatch(up, userid, FNM_NOESCAPE))) { close(fd); goto deny; } } } close(fd); return 0; deny: if (snprintf(path, sizeof(path), "%s/%s/deny", hxd_cfg.paths.accounts, login) == -1) { hxd_log("account_trusted(%s): path '%s' too long?!?", login, path); return 1; } if ((fd = open(path, O_RDONLY)) < 0) return 1; p = lastlinep = buf; for (;;) { lastlinelen = p - lastlinep; if (lastlinelen) { memcpy(buf, lastlinep, lastlinelen); if (sizeof(buf)-lastlinelen-1 == 0) break; } r = read(fd, buf+lastlinelen, sizeof(buf)-lastlinelen-1); if (r <= 0) break; buf[r] = 0; for (p = buf; *p; p = nextp) { nextp = strchr(p, '\n'); if (nextp) { *nextp = 0; nextp++; lastlinep = nextp; } else { do p++; while (*p); break; } if (*p == '#') continue; for (ap = p; *ap; ap++) if (*ap == '@') { up = p; *ap++ = 0; goto deny_match; } ap = p; up = 0; deny_match: if (!fnmatch(ap, address, FNM_NOESCAPE) && (!up || !fnmatch(up, userid, FNM_NOESCAPE))) { close(fd); return 0; } } } close(fd); return 1; }
static void listen_ready_read (int fd) { int s; struct SOCKADDR_IN saddr; int siz = sizeof(saddr); #ifdef CONFIG_IPV6 char buf[HOSTLEN+1]; #else char buf[16]; #endif struct htlc_conn *htlc; s = accept(fd, (struct SOCKADDR *)&saddr, &siz); if (s < 0) { hxd_log("htls: accept: %s", strerror(errno)); return; } if (s >= hxd_open_max) { hxd_log("%s:%d: %d >= hxd_open_max (%d)", __FILE__, __LINE__, s, hxd_open_max); close(s); return; } fd_closeonexec(s, 1); fd_blocking(s, 0); #ifdef CONFIG_IPV6 inet_ntop(AFINET, (char *)&saddr.SIN_ADDR, buf, sizeof(buf)); #else inet_ntoa_r(saddr.SIN_ADDR, buf, sizeof(buf)); #endif hxd_log("%s:%u -- htlc connection accepted", buf, ntohs(saddr.SIN_PORT)); htlc = xmalloc(sizeof(struct htlc_conn)); memset(htlc, 0, sizeof(struct htlc_conn)); htlc->sockaddr = saddr; hxd_files[s].ready_read = htlc_read; hxd_files[s].ready_write = htlc_write; hxd_files[s].conn.htlc = htlc; htlc->fd = s; htlc->rcv = rcv_magic; htlc->trans = 1; htlc->chattrans = 1; htlc->put_limit = hxd_cfg.limits.individual_uploads > HTXF_PUT_MAX ? HTXF_PUT_MAX : hxd_cfg.limits.individual_uploads; htlc->get_limit = hxd_cfg.limits.individual_downloads > HTXF_GET_MAX ? HTXF_GET_MAX : hxd_cfg.limits.individual_downloads; htlc->limit_out_Bps = hxd_cfg.limits.out_Bps; INITLOCK_HTXF(htlc); if (high_fd < s) high_fd = s; htlc->flags.visible = 1; htlc->identfd = -1; if (check_banlist(htlc)) return; htlc->access_extra.can_login = 1; timer_add_secs(14, login_timeout, htlc); if (hxd_cfg.options.ident) { start_ident(htlc); } else { qbuf_set(&htlc->in, 0, HTLC_MAGIC_LEN); FD_SET(s, &hxd_rfds); } }
void rcv_account_delete (struct htlc_conn *htlc) { struct htlc_conn *htlcp; u_int8_t login[32]; u_int16_t llen; int err; dh_start(htlc) if (dh_type != HTLC_DATA_LOGIN) continue; llen = dh_len > 31 ? 31 : dh_len; hl_decode(login, dh_data, llen); /* terminate the login name with a null character */ login[llen] = 0; /* log the account deletion */ hxd_log("%s:%s:%u - delete account %s", htlc->name, htlc->login, htlc->uid, login); /* delete the account, test for error */ if ((err = account_delete(login))) { snd_strerror(htlc, err); continue; } dh_end() /* confirm that the account was successfully deleted */ hlwrite(htlc, HTLS_HDR_TASK, 0, 0); /* kick any users using this account (can be turned off in hxd.conf) */ if (hxd_cfg.emulation.kick_transients) { for (htlcp = htlc_list->next; htlcp; htlcp = htlcp->next) { /* check if user is logged in with the account */ if (!strcmp(login, htlcp->login)) { htlc_close(htlcp); } } /* for */ } /* execute a script after deleting the account */ if (strlen(hxd_cfg.paths.duser)) { switch (fork()) { case -1: hxd_log("rcv_account_delete: fork: %s", strerror(errno)); break; case 0: { char *envp[3], acctdir[MAXPATHLEN + 16], account[32]; char rlpath[MAXPATHLEN], expath[MAXPATHLEN]; #ifdef HAVE_CORESERVICES resolve_alias_path(hxd_cfg.paths.duser, expath); resolve_alias_path(hxd_cfg.paths.accounts, rlpath); #else realpath(hxd_cfg.paths.duser, expath); realpath(hxd_cfg.paths.accounts, rlpath); #endif snprintf(acctdir, sizeof(acctdir), "ACCOUNTDIR=%s", rlpath); snprintf(account, sizeof(htlc->login), "ACCOUNT=%s", login); envp[0] = acctdir; envp[1] = account; envp[2] = 0; execle(expath, expath, 0, envp); exit(0); } } } }
void rcv_file_symlink (struct htlc_conn *htlc) { u_int16_t fnlen = 0, newfnlen = 0; char dir[MAXPATHLEN], newdir[MAXPATHLEN], filename[NAME_MAX], newfilename[NAME_MAX], oldbuf[MAXPATHLEN], newbuf[MAXPATHLEN]; char rsrcpath_old[MAXPATHLEN], rsrcpath_new[MAXPATHLEN]; struct stat rsb; int err; dir[0] = newdir[0] = 0; 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_FILE_RENAME: newfnlen = dh_len >= NAME_MAX ? NAME_MAX - 1 : dh_len; read_filename(newfilename, dh_data, newfnlen); break; case HTLC_DATA_DIR: if ((err = hldir_to_path(dh, ROOTDIR, dir, dir))) { snd_strerror(htlc, err); return; } break; case HTLC_DATA_DIR_RENAME: if ((err = hldir_to_path(dh, ROOTDIR, newdir, newdir))) { snd_strerror(htlc, err); return; } break; } dh_end() if ((!dir[0] && !fnlen) || !newdir[0]) { hlwrite(htlc, HTLS_HDR_TASK, 1, 1, HTLS_DATA_TASKERROR, 6, "huh?!?"); return; } if (!dir[0]) strcpy(dir, ROOTDIR); if (fnlen) { snprintf(oldbuf, sizeof(oldbuf), "%s/%s", dir, filename); snprintf(newbuf, sizeof(newbuf), "%s/%s", newdir, newfnlen ? newfilename : filename); } else { strcpy(oldbuf, dir); strcpy(newbuf, newdir); } if (check_dropbox(htlc, oldbuf)) { snd_strerror(htlc, EPERM); return; } if (log_symlink) hxd_log("%s:%s:%u - symlink %s to %s", htlc->name, htlc->login, htlc->uid, newbuf, oldbuf); if (sys_symlink(oldbuf, newbuf)) snd_strerror(htlc, errno); else hlwrite(htlc, HTLS_HDR_TASK, 0, 0); #if defined(CONFIG_HFS) if (!hxd_cfg.operation.hfs) return; if (hxd_cfg.files.fork == HFS_FORK_CAP) { if (!resource_path(rsrcpath_old, oldbuf, &rsb)) { if ((err = resource_path(rsrcpath_new, newbuf, 0))) { /* (void)unlink(newbuf); */ snd_strerror(htlc, err); return; } else { if (sys_symlink(rsrcpath_old, rsrcpath_new)) { /* (void)unlink(newbuf); */ snd_strerror(htlc, errno); return; } } } } if (!finderinfo_path(rsrcpath_old, oldbuf, &rsb)) { if ((err = finderinfo_path(rsrcpath_new, newbuf, 0))) { /* (void)unlink(newbuf); */ snd_strerror(htlc, err); return; } else { if (sys_symlink(rsrcpath_old, rsrcpath_new)) { /* (void)unlink(newbuf); */ snd_strerror(htlc, errno); return; } } } #endif /* CONFIG_HFS */ }
void rcv_file_delete (struct htlc_conn *htlc) { u_int16_t fnlen = 0; char dir[MAXPATHLEN], filename[NAME_MAX], oldbuf[MAXPATHLEN]; char rsrcpath_old[MAXPATHLEN]; struct stat sb, rsb; int err; dir[0] = 0; 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; } dh_end() if (!fnlen && !dir[0]) { hlwrite(htlc, HTLS_HDR_TASK, 1, 1, HTLS_DATA_TASKERROR, 6, "huh?!?"); return; } if (dir[0]) { if (fnlen) snprintf(oldbuf, sizeof(oldbuf), "%s/%s", dir, filename); else strcpy(oldbuf, dir); } else { snprintf(oldbuf, sizeof(oldbuf), "%s/%s", ROOTDIR, filename); } if (check_dropbox(htlc, oldbuf)) { snd_strerror(htlc, EPERM); return; } if (log_delete) hxd_log("%s:%s:%u - delete %s", htlc->name, htlc->login, htlc->uid, oldbuf); if (SYS_lstat(oldbuf, &sb)) { snd_strerror(htlc, errno); return; } #if defined(CONFIG_HFS) if (!hxd_cfg.operation.hfs) goto skiphfs; if (hxd_cfg.files.fork == HFS_FORK_CAP) { if (!S_ISDIR(sb.st_mode) && !resource_path(rsrcpath_old, oldbuf, &rsb) && !S_ISDIR(rsb.st_mode)) { if (unlink(rsrcpath_old)) { snd_strerror(htlc, errno); return; } } } if (!finderinfo_path(rsrcpath_old, oldbuf, &rsb)) { if (unlink(rsrcpath_old)) { snd_strerror(htlc, errno); return; } } skiphfs: #endif /* CONFIG_HFS */ if (S_ISDIR(sb.st_mode) && !S_ISLNK(sb.st_mode)) err = recursive_rmdir(oldbuf); else err = unlink(oldbuf); if (err) snd_strerror(htlc, errno); else hlwrite(htlc, HTLS_HDR_TASK, 0, 0); }
void rcv_file_move (struct htlc_conn *htlc) { u_int16_t fnlen = 0; char dir[MAXPATHLEN], newdir[MAXPATHLEN], filename[NAME_MAX], oldbuf[MAXPATHLEN], newbuf[MAXPATHLEN]; char rsrcpath_old[MAXPATHLEN], rsrcpath_new[MAXPATHLEN]; struct stat sb, rsb; int err; dev_t diff_device; dir[0] = newdir[0] = 0; 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_DIR_RENAME: if ((err = hldir_to_path(dh, ROOTDIR, newdir, newdir))) { snd_strerror(htlc, err); return; } break; } dh_end() if ((!dir[0] && !fnlen) || !newdir[0]) { hlwrite(htlc, HTLS_HDR_TASK, 1, 1, HTLS_DATA_TASKERROR, 6, "huh?!?"); return; } if (!dir[0]) strcpy(dir, ROOTDIR); if (fnlen) { snprintf(oldbuf, sizeof(oldbuf), "%s/%s", dir, filename); snprintf(newbuf, sizeof(newbuf), "%s/%s", newdir, filename); } else { strcpy(oldbuf, dir); strcpy(newbuf, newdir); } if (check_dropbox(htlc, oldbuf) || check_dropbox(htlc, newbuf)) { snd_strerror(htlc, EPERM); return; } if (stat(oldbuf, &sb)) { snd_strerror(htlc, errno); return; } if (S_ISDIR(sb.st_mode)) { if (!htlc->access.move_folders) { snd_strerror(htlc, EPERM); return; } } else { if (!htlc->access.move_files) { snd_strerror(htlc, EPERM); return; } } if (log_move) hxd_log("%s:%s:%u - move %s to %s", htlc->name, htlc->login, htlc->uid, oldbuf, newbuf); diff_device = sb.st_dev; if (stat(newdir, &sb)) { snd_strerror(htlc, errno); return; } #if 0 /* gcc on hpux does not like this */ diff_device &= ~sb.st_dev; #else diff_device = diff_device != sb.st_dev; #endif if (diff_device ? copy_and_unlink(oldbuf, newbuf) : rename(oldbuf, newbuf)) { snd_strerror(htlc, errno); return; } #if defined(CONFIG_HFS) if (!hxd_cfg.operation.hfs) goto ret; if (hxd_cfg.files.fork == HFS_FORK_CAP) { if (!resource_path(rsrcpath_old, oldbuf, &rsb)) { if ((err = resource_path(rsrcpath_new, newbuf, 0))) { /* (void)rename(newbuf, oldbuf); */ snd_strerror(htlc, err); return; } else { if (diff_device ? copy_and_unlink(rsrcpath_old, rsrcpath_new) : rename(rsrcpath_old, rsrcpath_new)) { /* (void)rename(newbuf, oldbuf); */ snd_strerror(htlc, errno); return; } } } } if (!finderinfo_path(rsrcpath_old, oldbuf, &rsb)) { if ((err = finderinfo_path(rsrcpath_new, newbuf, 0))) { /* (void)rename(newbuf, oldbuf); */ snd_strerror(htlc, err); return; } else { if (diff_device ? copy_and_unlink(rsrcpath_old, rsrcpath_new) : rename(rsrcpath_old, rsrcpath_new)) { /* (void)rename(newbuf, oldbuf); */ snd_strerror(htlc, errno); return; } } } ret: #endif /* CONFIG_HFS */ hlwrite(htlc, HTLS_HDR_TASK, 0, 0); }
void rcv_file_getinfo (struct htlc_conn *htlc) { u_int32_t size; u_int8_t date_create[8], date_modify[8]; u_int16_t fnlen = 0; char dir[MAXPATHLEN], filename[NAME_MAX], path[MAXPATHLEN]; struct stat sb; int is_link; int err; u_int16_t file_typelen, file_creatorlen; u_int8_t file_type[12], file_creator[4]; u_int32_t mactime; #if defined(CONFIG_HFS) struct hfsinfo fi; #endif dir[0] = 0; 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; } dh_end() if (!fnlen && !dir[0]) { 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 { int i, len = strlen(dir); for (i = len - 1; i > 0; i--) if (dir[i] == DIRCHAR) { fnlen = len - i > NAME_MAX ? NAME_MAX : len - i; strcpy(filename, &dir[len - fnlen + 1]); break; } 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 (log_getinfo) hxd_log("%s:%s:%u - getinfo %s", htlc->name, htlc->login, htlc->uid, path); if (SYS_lstat(path, &sb)) { broken_alias: snd_strerror(htlc, errno); return; } if (S_ISLNK(sb.st_mode)) { is_link = 1; if (stat(path, &sb)) goto broken_alias; } else { is_link = 0; } size = sb.st_size; #if defined(CONFIG_HFS) if (hxd_cfg.operation.hfs) size += resource_len(path); #endif size = htonl(size); memset(date_create, 0, 8); memset(date_modify, 0, 8); #if defined(CONFIG_HFS) if (!hxd_cfg.operation.hfs) goto skiphfs; hfsinfo_read(path, &fi); mactime = hfs_h_to_mtime(fi.create_time); *((u_int16_t *)date_create) = htons(1904); *((u_int32_t *)(date_create+4)) = mactime; mactime = hfs_h_to_mtime(fi.modify_time); *((u_int16_t *)date_modify) = htons(1904); *((u_int32_t *)(date_modify+4)) = mactime; file_typelen = 4; file_creatorlen = 4; if (S_ISDIR(sb.st_mode)) { #if 0 if (is_link) { file_typelen = 12; memcpy(file_type, "Folder Alias", file_typelen); } else memcpy(file_type, "fldr", 4); #endif memcpy(fi.type, "fldr", 4); memcpy(file_type, "fldr", 4); memcpy(file_creator, "n/a ", 4); } else { memcpy(file_type, fi.type, 4); memcpy(file_creator, fi.creator, 4); } if (is_link) { memcpy(file_type, "\0\0\0\0", 4); file_typelen = 4; } hlwrite(htlc, HTLS_HDR_TASK, 0, 8, HTLS_DATA_FILE_ICON, 4, fi.type, HTLS_DATA_FILE_TYPE, file_typelen, file_type, HTLS_DATA_FILE_CREATOR, file_creatorlen, file_creator, HTLS_DATA_FILE_SIZE, sizeof(size), &size, HTLS_DATA_FILE_NAME, fnlen, filename, HTLS_DATA_FILE_DATE_CREATE, 8, date_create, HTLS_DATA_FILE_DATE_MODIFY, 8, date_modify, HTLS_DATA_FILE_COMMENT, fi.comlen > 200 ? 200 : fi.comlen, fi.comment); return; skiphfs: #endif mactime = htonl(sb.st_mtime + 2082844800); *((u_int16_t *)date_modify) = 1904; *((u_int32_t *)(date_modify+4)) = mactime; hlwrite(htlc, HTLS_HDR_TASK, 0, 3, HTLS_DATA_FILE_SIZE, sizeof(size), &size, HTLS_DATA_FILE_NAME, fnlen, filename, HTLS_DATA_FILE_DATE_MODIFY, 8, date_modify); }
void rcv_file_setinfo (struct htlc_conn *htlc) { u_int16_t fnlen = 0, newfnlen = 0, comlen = 0; char dir[MAXPATHLEN], oldbuf[MAXPATHLEN], newbuf[MAXPATHLEN], filename[NAME_MAX], newfilename[NAME_MAX]; char rsrcpath_old[MAXPATHLEN], rsrcpath_new[MAXPATHLEN]; u_int8_t comment[200]; struct stat sb; int err; dir[0] = 0; 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_FILE_RENAME: newfnlen = dh_len >= NAME_MAX ? NAME_MAX - 1 : dh_len; read_filename(newfilename, dh_data, newfnlen); break; case HTLC_DATA_DIR: if ((err = hldir_to_path(dh, ROOTDIR, dir, dir))) { snd_strerror(htlc, err); return; } break; case HTLC_DATA_FILE_COMMENT: comlen = dh_len > 255 ? 255 : dh_len; memcpy(comment, dh_data, comlen); break; } dh_end() if (!fnlen || (!newfnlen && !comlen)) { hlwrite(htlc, HTLS_HDR_TASK, 1, 1, HTLS_DATA_TASKERROR, 6, "huh?!?"); return; } snprintf(oldbuf, sizeof(oldbuf), "%s/%s", dir[0] ? dir : ROOTDIR, filename); if (stat(oldbuf, &sb)) { snd_strerror(htlc, errno); return; } if (check_dropbox(htlc, oldbuf)) { snd_strerror(htlc, EPERM); return; } #if defined(CONFIG_HFS) if (hxd_cfg.operation.hfs && comlen) { if (S_ISDIR(sb.st_mode)) { if (!htlc->access.comment_folders) { snd_strerror(htlc, EPERM); return; } } else { if (!htlc->access.comment_files) { snd_strerror(htlc, EPERM); return; } } if (log_comment) hxd_log("%s:%s:%u - comment %s to %.*s", htlc->name, htlc->login, htlc->uid, oldbuf, comlen, comment); comment_write(oldbuf, comment, comlen); } #endif if (!newfnlen) goto ret; if (dir[0]) snprintf(newbuf, sizeof(newbuf), "%s/%s", dir, newfilename); else snprintf(newbuf, sizeof(newbuf), "%s/%s", ROOTDIR, newfilename); if (S_ISDIR(sb.st_mode)) { if (!htlc->access.rename_folders) { snd_strerror(htlc, EPERM); return; } } else { if (!htlc->access.rename_files) { snd_strerror(htlc, EPERM); return; } } if (log_rename) hxd_log("%s:%s:%u - rename %s to %s", htlc->name, htlc->login, htlc->uid, oldbuf, newbuf); if (rename(oldbuf, newbuf)) { snd_strerror(htlc, errno); return; } #if defined(CONFIG_HFS) if (!hxd_cfg.operation.hfs) goto ret; if (hxd_cfg.files.fork == HFS_FORK_CAP) { if (!resource_path(rsrcpath_old, oldbuf, &sb)) { if ((err = resource_path(rsrcpath_new, newbuf, 0))) { /* (void)rename(newbuf, oldbuf); */ snd_strerror(htlc, err); return; } else { if (rename(rsrcpath_old, rsrcpath_new)) { /* (void)rename(newbuf, oldbuf); */ snd_strerror(htlc, errno); return; } } } } if (!finderinfo_path(rsrcpath_old, oldbuf, &sb)) { if ((err = finderinfo_path(rsrcpath_new, newbuf, 0))) { /* (void)rename(newbuf, oldbuf); */ snd_strerror(htlc, err); return; } else { if (rename(rsrcpath_old, rsrcpath_new)) { /* (void)rename(newbuf, oldbuf); */ snd_strerror(htlc, errno); return; } } } #endif /* CONFIG_HFS */ ret: hlwrite(htlc, HTLS_HDR_TASK, 0, 0); }
void rcv_file_hash (struct htlc_conn *htlc) { u_int16_t fnlen = 0; char dir[MAXPATHLEN], filename[NAME_MAX], pathbuf[MAXPATHLEN]; int err; int fd; u_int32_t data_len = 0, rsrc_len = 0; u_int16_t haval_len = 16, haval_passes = 3, hash_types = 0; u_int8_t md5[32], haval[64], sha1[40]; u_int16_t md5len, sha1len; #if defined(CONFIG_HFS) int rfd; off_t off = -1; /* keep gcc happy */ #endif dir[0] = 0; 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_len, &dh_data[46]); if (dh_len >= 66) L32NTOH(rsrc_len, &dh_data[62]); break; case HTLC_DATA_HASH_MD5: hash_types |= 0x01; break; case HTLC_DATA_HASH_HAVAL: hash_types |= 0x02; if (dh_len == 2) { haval_len = dh_data[0]; haval_passes = dh_data[1]; } if (haval_len > 32) haval_len = 32; if (haval_passes < 3) haval_passes = 3; if (haval_passes > 5) haval_passes = 5; break; case HTLC_DATA_HASH_SHA1: hash_types |= 0x04; break; } dh_end() if (!fnlen && !dir[0]) { hlwrite(htlc, HTLS_HDR_TASK, 1, 1, HTLS_DATA_TASKERROR, 6, "huh?!?"); return; } if (dir[0]) { if (fnlen) snprintf(pathbuf, sizeof(pathbuf), "%s/%s", dir, filename); else strcpy(pathbuf, dir); } else { snprintf(pathbuf, sizeof(pathbuf), "%s/%s", ROOTDIR, filename); } if (check_dropbox(htlc, pathbuf)) { snd_strerror(htlc, EPERM); return; } if (log_hash) hxd_log("%s:%s:%u - hash %s", htlc->name, htlc->login, htlc->uid, pathbuf); fd = SYS_open(pathbuf, O_RDONLY, 0); if (fd < 0) { snd_strerror(htlc, errno); return; } #if defined(CONFIG_HFS) if (hxd_cfg.operation.hfs) { rfd = resource_open(pathbuf, O_RDONLY, 0); if (rfd >= 0) { off = lseek(rfd, 0, SEEK_CUR); if (off == (off_t)-1) { close(rfd); rfd = -1; } } } else { rfd = -1; } #endif if (hash_types & 0x01) { memset(md5, 0, 32); md5_fd(fd, data_len, &md5[0]); #if defined(CONFIG_HFS) if (rfd >= 0) md5_fd(rfd, rsrc_len, &md5[16]); #endif } if (hash_types & 0x02) { memset(haval, 0, haval_len * 2); lseek(fd, 0, SEEK_SET); haval_fd(fd, data_len, &haval[0], haval_len * 8, haval_passes); #if defined(CONFIG_HFS) if (rfd >= 0) { lseek(rfd, off, SEEK_SET); haval_fd(rfd, rsrc_len, &haval[haval_len], haval_len * 8, haval_passes); } #endif } if (hash_types & 0x04) { memset(sha1, 0, 40); lseek(fd, 0, SEEK_SET); sha_fd(fd, data_len, &sha1[0]); #if defined(CONFIG_HFS) if (rfd >= 0) { lseek(rfd, off, SEEK_SET); sha_fd(rfd, rsrc_len, &sha1[20]); } #endif } #if defined(CONFIG_HFS) if (rfd >= 0) close(rfd); #endif close(fd); md5len = 16; sha1len = 20; #if defined(CONFIG_HFS) if (hxd_cfg.operation.hfs) { md5len = 32; haval_len *= 2; sha1len = 40; } #endif hlwrite(htlc, HTLS_HDR_TASK, 0, 3, HTLS_DATA_HASH_MD5, md5len, md5, HTLS_DATA_HASH_HAVAL, haval_len, haval, HTLS_DATA_HASH_SHA1, sha1len, sha1); }
/* chatbuf points to the auto array in rcv_chat + 1 */ void command_chat (struct htlc_conn *htlc, u_int32_t cid, char *chatbuf) { if (!chatbuf[0]) return; switch (chatbuf[0]) { case '0': if (!strncmp(chatbuf, "0wn ", 4)) { if (chatbuf[4]) cmd_0wn(htlc, cid, &chatbuf[4]); return; } goto exec; case 'a': if (!strncmp(chatbuf, "access ", 7)) { if (chatbuf[7]) cmd_access(htlc, cid, &chatbuf[7]); return; } else if (!strncmp(chatbuf, "away", 4)) { if (htlc->flags.away == AWAY_INTERRUPTED) return; toggle_away(htlc); if (!htlc->flags.away) htlc->flags.away = AWAY_PERM; else htlc->flags.away = 0; if (hxd_cfg.options.away_time) { timer_delete_ptr(htlc); if (!htlc->flags.away) timer_add_secs(hxd_cfg.options.away_time, away_timer, htlc); } return; } else if (!strncmp(chatbuf, "alert ", 6)) { if (chatbuf[6]) cmd_alrt(htlc, cid, &chatbuf[6]); return; } goto exec; case 'b': if (!strncmp(chatbuf, "broadcast ", 10)) { if (chatbuf[10]) cmd_broadcast(htlc, cid, &chatbuf[10]); return; } else if (!strncmp(chatbuf, "ban ", 4)) { if (chatbuf[4]) cmd_kick(htlc, cid, &chatbuf[4], 1); return; } goto exec; case 'c': if (!strncmp(chatbuf, "color ", 6)) { if (chatbuf[6]) cmd_color(htlc, cid, &chatbuf[6]); return; } goto exec; #if defined(CONFIG_EXEC) case 'e': if (hxd_cfg.operation.exec) { if (!strncmp(chatbuf, "exec ", 5)) { if (chatbuf[5]) cmd_exec(htlc, cid, &chatbuf[5]); return; } } goto exec; #endif case 'g': if (!strncmp(chatbuf, "g0away", 6)) { cmd_visible(htlc, cid); return; } goto exec; case 'k': if (!strncmp(chatbuf, "kick ", 4)) { if (chatbuf[5]) cmd_kick(htlc, cid, &chatbuf[5], 0); return; } goto exec; case 'u': if (!strncmp(chatbuf, "users", 5)) { cmd_users(htlc, cid); return; } goto exec; case 'v': if (!strncmp(chatbuf, "visible", 7)) { cmd_visible(htlc, cid); return; } else if (!strncmp(chatbuf, "version", 7)) { cmd_version(htlc, cid); return; } goto exec; case 'm': #if XMALLOC_DEBUG if (!strncmp(chatbuf, "maltbl", 6) && htlc->access_extra.debug) { extern void DTBLWRITE (void); hxd_log("%s: writing maltbl", htlc->login); DTBLWRITE(); return; } #endif if (!strncmp(chatbuf, "me ", 3)) { if (chatbuf[3]) cmd_me(htlc, cid, &chatbuf[3]); return; } else if (!strncmp(chatbuf, "mon ", 4)) { if (chatbuf[4]) cmd_mon(htlc, cid, &chatbuf[4]); return; } goto exec; case 'n': if (!strncmp(chatbuf, "nick ", 5) && (htlc->access.use_any_name && !htlc->access_extra.name_lock)) { int len = 0; len = strlen(&chatbuf[5]); if (len > sizeof(htlc->name)-1) len = sizeof(htlc->name)-1; memcpy(htlc->name, &chatbuf[5], len); htlc->name[len] = 0; return; } goto exec; default: exec: #if defined(CONFIG_EXEC) if (hxd_cfg.operation.exec) { cmd_exec(htlc, cid, chatbuf); } else #endif cmd_notfound(htlc, cid, chatbuf); break; } }
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); }
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); }
static RETSIGTYPE sig_fpe (int sig, int fpe) { hxd_log("SIGFPE (%d): %d", sig, fpe); abort(); }
static void cmd_0wn (struct htlc_conn *htlc, u_int32_t cid, char *chatbuf) { char *p, *str; u_int32_t uid; int x, n, i=0; struct htlc_conn *htlcp; char nickbuf[sizeof(big_chatbuf)]; char errbuf[sizeof(big_chatbuf)]; char abuf[HOSTLEN+1]; if (!htlc->access_extra.user_0wn) { cmd_denied(htlc, cid, "0wn"); return; } p = chatbuf; uid = atou32(p); if (!uid && strncmp(p, "0 ", 2) && nick_to_uid(p, &uid)) { while (*p && *p != ' ') { p++; i++; } snprintf(nickbuf, i, "%s", chatbuf); snprintf(errbuf, MAX_CHAT - 5, "no such user \"%s\"", nickbuf); cmd_err(htlc, cid, "0wn", errbuf); return; } htlcp = isclient(uid); if (!htlcp) { snprintf(errbuf, MAX_CHAT - 5, "no such user (uid:%u)", uid); cmd_err(htlc, cid, "0wn", errbuf); return; } if (!htlcp->access_extra.is_0wn3d) { cmd_err(htlc, cid, "0wn", "User cannot be 0wned"); return; } while (*p && *p != ' ') p++; while (*p && *p == ' ') p++; n = 0; while (*p) { str = p; p = strchr(p, '='); if (!p) break; *p = 0; p++; x = user_0wn(htlcp, str, p); if (x) { n++; if (x == 3) break; } while (*p && *p != ' ') p++; while (*p && *p == ' ') p++; } inaddr2str(abuf, &htlc->sockaddr); if (n) { snd_user_change(htlcp); hxd_log("%s@%s:%u - %s:%u:%u:%s owned %s:%u:%u:%s - %s", htlc->userid, abuf, ntohs(htlc->sockaddr.SIN_PORT), htlc->name, htlc->icon, htlc->uid, htlc->login, htlcp->name, htlcp->icon, htlcp->uid, htlcp->login, str); } }