/* add a string to a simple list */ void irlist_add_string(irlist_t *list, const char *str) { char *copy; copy = irlist_add(list, strlen(str) + 1); strcpy(copy, str); }
/* create a new transfer */ transfer *create_transfer(xdcc *xd, const char *nick, const char *hostname) { transfer *tr; dcc_options_t *dcc_options; ++(xd->file_fd_count); tr = irlist_add(&gdata.trans, sizeof(transfer)); t_initvalues(tr); tr->id = get_next_tr_id(); tr->nick = mystrdup(nick); tr->caps_nick = mystrdup(nick); caps(tr->caps_nick); tr->hostname = mystrdup(hostname); tr->xpack = xd; tr->maxspeed = xd->maxspeed; tr->net = gnetwork->net; tr->quietmode = gdata.quietmode; tr->passive_dcc = gdata.passive_dcc; tr->con.family = gnetwork->myip.sa.sa_family; tr->con.localport = 0; dcc_options = get_options(tr->nick); if (dcc_options != NULL) { if ((dcc_options->options & DCC_OPTION_IPV4) != 0) tr->con.family = AF_INET; if ((dcc_options->options & DCC_OPTION_IPV6) != 0) tr->con.family = AF_INET6; if ((dcc_options->options & DCC_OPTION_ACTIVE) != 0) tr->passive_dcc = 0; if ((dcc_options->options & DCC_OPTION_PASSIVE) != 0) tr->passive_dcc = 1; if ((dcc_options->options & DCC_OPTION_QUIET) != 0) tr->quietmode = 1; } return tr; }
/* check permissions and setup the upload transfer */ void upload_start(const char *nick, const char *hostname, const char *hostmask, const char *filename, const char *remoteip, const char *remoteport, const char *bytes, char *token) { upload *ul; char *uploaddir; char *tempstr; off_t len; updatecontext(); len = atoull(bytes); if (invalid_upload(nick, hostmask, len)) return; uploaddir = get_uploaddir(hostmask); if (uploaddir == NULL) { error_upload_start(nick, hostmask, "no uploaddir", "No uploaddir defined."); return; } if (disk_full(uploaddir) != 0) { error_upload_start(nick, hostmask, "disk full", "not enough free space on disk"); return; } if (file_uploading(filename) != 0) { error_upload_start(nick, hostmask, "upload running", "I'm already getting this file"); return; } if (max_uploads_reached() != 0) { error_upload_start(nick, hostmask, "too many uploads", "I'm already getting too many files"); return; } ul = irlist_add(&gdata.uploads, sizeof(upload)); l_initvalues(ul); ul->file = mystrdup(getfilename(filename)); ul->con.family = (strchr(remoteip, ':')) ? AF_INET6 : AF_INET; ul->con.remoteaddr = mystrdup(remoteip); ul->con.remoteport = atoi(remoteport); ul->totalsize = len; ul->nick = mystrdup(nick); ul->hostname = mystrdup(hostname); ul->uploaddir = mystrdup(uploaddir); ul->net = gnetwork->net; qupload_started(gnetwork->net, nick); tempstr = getsendname(ul->file); ioutput(OUT_S|OUT_L|OUT_D, COLOR_YELLOW, "DCC Send Accepted from %s on %s: %s (%" LLPRINTFMT "dkB)", nick, gnetwork->name, tempstr, (ul->totalsize / 1024)); mydelete(tempstr); if (gdata.mirc_dcc64) if (ul->totalsize > 0xFFFFFFFFL) ul->mirc_dcc64 = 1; if (ul->con.remoteport > 0U) { l_establishcon(ul); } else { /* Passive DCC */ l_setup_passive(ul, token); } }
/* create a new transfer */ transfer *create_transfer(xdcc *xd, const char *nick, const char *hostname) { transfer *tr; ++(xd->file_fd_count); tr = irlist_add(&gdata.trans, sizeof(transfer)); t_initvalues(tr); tr->id = get_next_tr_id(); tr->nick = mystrdup(nick); tr->caps_nick = mystrdup(nick); caps(tr->caps_nick); tr->hostname = mystrdup(hostname); tr->xpack = xd; tr->maxspeed = xd->maxspeed; tr->net = gnetwork->net; return tr; }
/* start a transfer later */ static void fetch_later(const userinput *const u, const char *uploaddir, char *name, char *url) { fetch_queue_t *fq; updatecontext(); fq = irlist_add(&gdata.fetch_queue, sizeof(fetch_queue_t)); fq->u.method = u->method; if (u->snick != NULL) { fq->u.snick = mystrdup(u->snick); } fq->u.fd = u->fd; fq->u.chat = u->chat; fq->net = gnetwork->net; fq->name = mystrdup(name); fq->url = mystrdup(url); fq->uploaddir = mystrdup(uploaddir); }
/* update or create an entry in the ignore list */ igninfo *get_ignore(const char *hostmask) { igninfo *ignore; for (ignore = irlist_get_head(&gdata.ignorelist); ignore; ignore = irlist_get_next(ignore)) { if (fnmatch(ignore->hostmask, hostmask, FNM_CASEFOLD) != 0) continue; ignore->lastcontact = gdata.curtime; return ignore; } ignore = irlist_add(&gdata.ignorelist, sizeof(igninfo)); ignore->hostmask = mystrdup(hostmask); ignore->lastcontact = gdata.curtime; return ignore; }
int setupdccchatout(const char *nick, const char *hostmask, const char *token) { char *msg; char *token2 = NULL; unsigned int rc; dccchat_t *chat; updatecontext(); chat = irlist_add(&gdata.dccchats, sizeof(dccchat_t)); chat->name = gnetwork->name; chat->status = DCCCHAT_UNUSED; chat->con.family = gnetwork->myip.sa.sa_family; rc = irc_open_listen(&(chat->con)); if (rc != 0) return 1; gdata.num_dccchats++; chat->status = DCCCHAT_LISTENING; chat->con.clientsocket = FD_UNUSED; chat->nick = mystrdup(nick); chat->net = gnetwork->net; chat->hostmask = mystrdup(hostmask); msg = setup_dcc_local(&(chat->con.local)); if (token != NULL) { privmsg_fast(nick, IRC_CTCP "DCC CHAT CHAT %s %s" IRC_CTCP, msg, token); } else { privmsg_fast(nick, IRC_CTCP "DCC CHAT CHAT %s" IRC_CTCP, msg); } my_getnameinfo(msg, maxtextlength -1, &(chat->con.local.sa)); chat->con.localaddr = mystrdup(msg); mydelete(token2); mydelete(msg); ioutput(OUT_S|OUT_L|OUT_D, COLOR_MAGENTA, "DCC CHAT sent to %s on %s, waiting for connection on %s", nick, chat->name, chat->con.localaddr); return 0; }
void parseconsole(void) { static char console_escape_seq[maxtextlengthshort]; unsigned char tempbuffa[INPUT_BUFFER_LENGTH]; int length; unsigned int linelength; userinput ui; unsigned int i, j; updatecontext(); bzero(console_escape_seq, sizeof(console_escape_seq)); if (is_fd_readable(fileno(stdin))) { memset(tempbuffa, 0, INPUT_BUFFER_LENGTH); length = read (fileno(stdin), &tempbuffa, INPUT_BUFFER_LENGTH); if (length < 1) { outerror(OUTERROR_TYPE_CRASH,"read from stdin failed: %s",(length<0) ? strerror(errno) : "EOF!"); } linelength = strlen(gdata.console_input_line); for (i=0; i<(unsigned int)length; i++) { if (console_escape_seq[0] != '\0') { size_t esc_len = strlen(console_escape_seq); if (esc_len < (maxtextlengthshort-2)) { console_escape_seq[esc_len]=tempbuffa[i]; esc_len++; if (((tempbuffa[i] >= 'a') && (tempbuffa[i] <= 'z')) || ((tempbuffa[i] >= 'A') && (tempbuffa[i] <= 'Z'))) { /* process sequence */ if (console_escape_seq[1] == '[') { if (console_escape_seq[esc_len-1] == 'A') { /* up */ int count; if (esc_len > 3) { count=atoi(&console_escape_seq[2]); } else { count=1; } while(count--) { if (gdata.console_history_offset) { gdata.console_history_offset--; strncpy(gdata.console_input_line, irlist_get_nth(&gdata.console_history, gdata.console_history_offset), INPUT_BUFFER_LENGTH-1); linelength = strlen(gdata.console_input_line); gdata.curcol = linelength; } } } else if (console_escape_seq[esc_len-1] == 'B') { /* down */ int count; if (esc_len > 3) { count=atoi(&console_escape_seq[2]); } else { count=1; } while(count--) { gdata.console_history_offset++; if (gdata.console_history_offset < irlist_size(&gdata.console_history)) { strncpy(gdata.console_input_line, irlist_get_nth(&gdata.console_history, gdata.console_history_offset), INPUT_BUFFER_LENGTH-1); linelength = strlen(gdata.console_input_line); gdata.curcol = linelength; } else { memset(gdata.console_input_line, 0, INPUT_BUFFER_LENGTH); linelength = 0; gdata.curcol = 0; } gdata.console_history_offset = min2(gdata.console_history_offset,irlist_size(&gdata.console_history)); } } else if (console_escape_seq[esc_len-1] == 'C') { /* right */ int count; if (esc_len > 3) { count=atoi(&console_escape_seq[2]); } else { count=1; } gdata.curcol += count; if (gdata.curcol > linelength) gdata.curcol = linelength; } else if (console_escape_seq[esc_len-1] == 'D') { /* left */ unsigned int count; if (esc_len > 3) { count=atoi(&console_escape_seq[2]); } else { count=1; } if (count <= gdata.curcol) gdata.curcol -= count; } /* else ignore */ } /* else ignore */ memset(console_escape_seq, 0, maxtextlengthshort); } } else { /* sequence is too long, ignore */ memset(console_escape_seq, 0, maxtextlengthshort); } } else if (tempbuffa[i] == '\x1b') { console_escape_seq[0]=tempbuffa[i]; } else if ((tempbuffa[i] == '\t') && gdata.console_input_line[0]) { if (!gdata.attop) gototop(); j = u_expand_command(); gdata.curcol += j; linelength += j; } else if (tempbuffa[i] == '\n') { char *hist; hist = irlist_get_tail(&gdata.console_history); if ((!hist || strcmp(hist,gdata.console_input_line)) && gdata.console_input_line[0]) { hist = irlist_add(&gdata.console_history, linelength+1); strncpy(hist, gdata.console_input_line, linelength); } if (irlist_size(&gdata.console_history) > MAX_HISTORY_SIZE) { irlist_delete(&gdata.console_history, irlist_get_head(&gdata.console_history)); } gdata.console_history_offset = irlist_size(&gdata.console_history); if (!gdata.attop) gototop(); u_fillwith_console(&ui,gdata.console_input_line); u_parseit(&ui); gdata.curcol=0; memset(gdata.console_input_line, 0, INPUT_BUFFER_LENGTH); } else if (isprintable(tempbuffa[i])) { if (linelength < (INPUT_BUFFER_LENGTH-2)) { for (j=linelength; j>gdata.curcol; j--) { gdata.console_input_line[j] = gdata.console_input_line[j-1]; } gdata.console_input_line[gdata.curcol]=tempbuffa[i]; gdata.curcol++; linelength++; } } else if (tempbuffa[i] == gdata.startup_tio.c_cc[VINTR]) { } else if (tempbuffa[i] == gdata.startup_tio.c_cc[VQUIT]) { } else if (tempbuffa[i] == gdata.startup_tio.c_cc[VERASE]) { if (gdata.curcol) { for (j=gdata.curcol-1; j<linelength; j++) { gdata.console_input_line[j] = gdata.console_input_line[j+1]; } linelength--; gdata.console_input_line[linelength] = '\0'; gdata.curcol--; } } else if (tempbuffa[i] == gdata.startup_tio.c_cc[VWERASE]) { while (gdata.curcol && (gdata.console_input_line[gdata.curcol-1] == ' ')) { for (j=gdata.curcol-1; j<linelength; j++) { gdata.console_input_line[j] = gdata.console_input_line[j+1]; } linelength--; gdata.console_input_line[linelength] = '\0'; gdata.curcol--; } while (gdata.curcol && (gdata.console_input_line[gdata.curcol-1] != ' ')) { for (j=gdata.curcol-1; j<linelength; j++) { gdata.console_input_line[j] = gdata.console_input_line[j+1]; } linelength--; gdata.console_input_line[linelength] = '\0'; gdata.curcol--; } while (gdata.curcol && (gdata.console_input_line[gdata.curcol-1] == ' ')) { for (j=gdata.curcol-1; j<linelength; j++) { gdata.console_input_line[j] = gdata.console_input_line[j+1]; } linelength--; gdata.console_input_line[linelength] = '\0'; gdata.curcol--; } } else if (tempbuffa[i] == gdata.startup_tio.c_cc[VKILL]) { } else if (tempbuffa[i] == gdata.startup_tio.c_cc[VEOF]) { } else if (tempbuffa[i] == gdata.startup_tio.c_cc[VSTART]) { } else if (tempbuffa[i] == gdata.startup_tio.c_cc[VSTOP]) { } else if (tempbuffa[i] == gdata.startup_tio.c_cc[VSUSP]) { } else if (tempbuffa[i] == gdata.startup_tio.c_cc[VLNEXT]) { } else if (tempbuffa[i] == gdata.startup_tio.c_cc[VREPRINT]) { } else if (tempbuffa[i] == gdata.startup_tio.c_cc[VDISCARD]) { } else if (tempbuffa[i] == '\x01') /* Ctrl-A */ { gdata.curcol = 0; } else if (tempbuffa[i] == '\x05') /* Ctrl-E */ { gdata.curcol = linelength; } } drawbot(); } }
/* start a transfer now */ static void fetch_now(const userinput *const u, const char *uploaddir, char *name, char *url) { off_t resumesize; fetch_curl_t *ft; char *fullfile; FILE *writefd; struct stat s; int retval; resumesize = 0; fullfile = mystrjoin(uploaddir, name, '/'); writefd = fopen(fullfile, "w+x"); /* NOTRANSLATE */ if ((writefd == NULL) && (errno == EEXIST)) { retval = stat(fullfile, &s); if (retval < 0) { outerror(OUTERROR_TYPE_WARN_LOUD, "Cant Stat Upload File '%s': %s", fullfile, strerror(errno)); a_respond(u, "File Error, File couldn't be opened for writing"); mydelete(fullfile); return; } resumesize = s.st_size; writefd = fopen(fullfile, "a+"); /* NOTRANSLATE */ } if (writefd == NULL) { outerror(OUTERROR_TYPE_WARN_LOUD, "Cant Access Upload File '%s': %s", fullfile, strerror(errno)); a_respond(u, "File Error, File couldn't be opened for writing"); mydelete(fullfile); return; } updatecontext(); ft = irlist_add(&fetch_trans, sizeof(fetch_curl_t)); ft->u.method = u->method; if (u->snick != NULL) { ft->u.snick = mystrdup(u->snick); } ft->u.fd = u->fd; ft->u.chat = u->chat; ft->id = ++fetch_id; ft->net = gnetwork->net; ft->name = mystrdup(name); ft->url = mystrdup(url); ft->uploaddir = mystrdup(uploaddir); ft->fullname = fullfile; fullfile = NULL; ft->writefd = writefd; ft->resumesize = resumesize; ft->errorbuf = mymalloc(CURL_ERROR_SIZE); ft->errorbuf[0] = 0; ft->starttime = gdata.curtime; if (curl_fetch(u, ft)) { clean_fetch(ft); return; } a_respond(u, "fetch '%s' started", ft->name); ++fetch_started; }
void t_transfersome (transfer * const t) { unsigned int j; int ii; ssize_t howmuch, howmuch2; size_t attempt; unsigned char *dataptr; off_t offset; #if defined(HAVE_FREEBSD_SENDFILE) struct sf_hdtr sendfile_header = {0, 0, 0, 0}; int jj; #endif updatecontext(); /* max bandwidth start.... */ if (!t->nomax && (t->maxspeed > 0)) { if (t->tx_bucket < TXSIZE) { t->overlimit = 1; return; /* over transfer limit */ } } else { t->tx_bucket = TXSIZE * MAXTXPERLOOP; } j = gdata.xdccsent[(gdata.curtime)%XDCC_SENT_SIZE] + gdata.xdccsent[(gdata.curtime-1)%XDCC_SENT_SIZE] + gdata.xdccsent[(gdata.curtime-2)%XDCC_SENT_SIZE] + gdata.xdccsent[(gdata.curtime-3)%XDCC_SENT_SIZE]; if ( gdata.maxb && (j >= gdata.maxb*1024)) { if (t->unlimited == 0) return; /* over overall limit */ } t->overlimit = 0; /* max bandwidth end.... */ do { attempt = min2(t->tx_bucket - (t->tx_bucket % TXSIZE), BUFFERSIZE); switch (gdata.transfermethod) { #if defined(HAVE_LINUX_SENDFILE) case TRANSFERMETHOD_LINUX_SENDFILE: offset = t->bytessent; howmuch = sendfile(t->con.clientsocket, t->xpack->file_fd, &offset, attempt); if (howmuch < 0 && ((errno == ENOSYS) || (errno == EOVERFLOW))) { /* sendfile doesn't work on this system, fall back */ outerror(OUTERROR_TYPE_WARN, "%s transfer method does not work on this system, falling back to next available method", "linux-sendfile"); gdata.transfermethod++; return; } else if (howmuch < 0 && errno != EAGAIN) { t_closeconn(t,"Unable to transfer data",errno); return; } else if (howmuch <= 0) { goto done; } howmuch2 = max2(0,howmuch); break; #endif #if defined(HAVE_FREEBSD_SENDFILE) case TRANSFERMETHOD_FREEBSD_SENDFILE: offset = t->bytessent; jj = sendfile(t->xpack->file_fd, t->con.clientsocket, offset, attempt, &sendfile_header, &offset, 0); if (jj < 0 && ((errno == ENOSYS) || (errno == EOPNOTSUPP))) { /* sendfile doesn't work on this system, fall back */ outerror(OUTERROR_TYPE_WARN, "%s transfer method does not work on this system, falling back to next available method", "freebsd-sendfile"); gdata.transfermethod++; return; } else if ((jj < 0) && (errno != EAGAIN)) { t_closeconn(t,"Unable to transfer data",errno); return; } /* * NOTE: according to freebsd man page, * sendfile can set EAGAIN and _STILL_ send data!! */ howmuch = (ssize_t)offset; if (howmuch == 0) { goto done; } howmuch2 = max2(0,howmuch); break; #endif case TRANSFERMETHOD_READ_WRITE: dataptr = gdata.sendbuff; if (t->xpack->file_fd_location != t->bytessent) { offset = lseek(t->xpack->file_fd, t->bytessent, SEEK_SET); if (offset != t->bytessent) { int errno2 = errno; outerror(OUTERROR_TYPE_WARN,"Can't seek location in file '%s': %s", t->xpack->file, strerror(errno)); t_closeconn(t, "Unable to locate data in file", errno2); return; } t->xpack->file_fd_location = t->bytessent; } howmuch = read(t->xpack->file_fd, dataptr, attempt); if (howmuch < 0 && errno != EAGAIN) { int errno2 = errno; outerror(OUTERROR_TYPE_WARN,"Can't read data from file '%s': %s", t->xpack->file, strerror(errno)); t_closeconn(t, "Unable to read data from file", errno2); return; } else if (howmuch <= 0) { goto done; } t->xpack->file_fd_location += howmuch; howmuch2 = send(t->con.clientsocket, dataptr, howmuch, MSG_NOSIGNAL); if (howmuch2 < 0 && errno != EAGAIN) { t_closeconn(t,"Connection Lost",errno); return; } howmuch2 = max2(0,howmuch2); break; #if defined(HAVE_MMAP) case TRANSFERMETHOD_MMAP: if (t->bytessent == t->xpack->st_size) { /* EOF */ goto done; } if (!t->mmap_info || ((ir_uint64)(t->bytessent) >= (t->mmap_info->mmap_offset + (ir_uint64)(t->mmap_info->mmap_size)))) { int callval_i; mmap_info_t *mm; if (t->mmap_info) { t->mmap_info->ref_count--; if (!t->mmap_info->ref_count) { callval_i = munmap(t->mmap_info->mmap_ptr, t->mmap_info->mmap_size); if (callval_i < 0) { outerror(OUTERROR_TYPE_WARN, "Couldn't munmap(): %s", strerror(errno)); } irlist_delete(&t->xpack->mmaps, t->mmap_info); } t->mmap_info = NULL; } /* see if what we want is already mapped */ for (mm = irlist_get_head(&t->xpack->mmaps); mm; mm = irlist_get_next(mm)) { if (mm->mmap_offset == (t->bytessent & ~(IR_MMAP_SIZE-1))) { t->mmap_info = mm; t->mmap_info->ref_count++; break; } } if (!t->mmap_info) { /* nope, add one */ mm = irlist_add(&t->xpack->mmaps, sizeof(mmap_info_t)); t->mmap_info = mm; mm->ref_count++; mm->mmap_offset = t->bytessent & ~(IR_MMAP_SIZE-1); mm->mmap_size = IR_MMAP_SIZE; if ((mm->mmap_offset + (ir_uint64)(mm->mmap_size)) > (ir_uint64)(t->xpack->st_size)) { mm->mmap_size = t->xpack->st_size - mm->mmap_offset; } mm->mmap_ptr = mmap(NULL, mm->mmap_size, PROT_READ, MAP_SHARED, t->xpack->file_fd, mm->mmap_offset); if ((mm->mmap_ptr == (unsigned char *)MAP_FAILED) || (!mm->mmap_ptr)) { irlist_delete(&t->xpack->mmaps, mm); t->mmap_info = NULL; if (errno == ENOMEM) { /* mmap doesn't work on this system, fall back */ outerror(OUTERROR_TYPE_WARN, "%s transfer method does not work on this system, falling back to next available method", "mmap"); gdata.transfermethod++; } else { t_closeconn(t,"Unable to access file",errno); } return; } if (gdata.debug > 53) { ioutput(OUT_S, COLOR_BLUE, "mmap() [%p] offset=0x%.8" LLPRINTFMT "X size=0x%.8" LLPRINTFMT "X", mm->mmap_ptr, (ir_uint64)(mm->mmap_offset), (ir_uint64)(mm->mmap_size)); } } } dataptr = t->mmap_info->mmap_ptr + t->bytessent - t->mmap_info->mmap_offset; if ((t->bytessent + attempt) > (t->mmap_info->mmap_offset + t->mmap_info->mmap_size)) { howmuch = (t->mmap_info->mmap_offset + t->mmap_info->mmap_size) - t->bytessent; } else { howmuch = attempt; } if (howmuch == 0) { /* EOF */ goto done; } howmuch2 = send(t->con.clientsocket, dataptr, howmuch, MSG_NOSIGNAL); if (howmuch2 < 0 && errno != EAGAIN) { t_closeconn(t,"Connection Lost",errno); return; } howmuch2 = max2(0,howmuch2); break; #endif default: t_closeconn(t,"Transfer Method unknown!", 0); return; } if (howmuch2 > 0) { t->con.lastcontact = gdata.curtime; } t->bytessent += howmuch2; gdata.xdccsum[gdata.curtime%XDCC_SENT_SIZE] += howmuch2; if (t->unlimited == 0) gdata.xdccsent[gdata.curtime%XDCC_SENT_SIZE] += howmuch2; t->tx_bucket -= howmuch2; j += howmuch2; gdata.totalsent += howmuch2; for (ii=0; ii<NUMBER_TRANSFERLIMITS; ii++) { gdata.transferlimits[ii].used += (ir_uint64)howmuch2; } if (gdata.debug > 51) { ioutput(OUT_S, COLOR_BLUE, "File %ld Write %ld", (long)howmuch, (long)howmuch2); } /* if over 50% send one to be fair */ if ( gdata.maxb && ((j*100) > (gdata.maxb*1024*50)) ) { goto done; } } while ((t->tx_bucket >= TXSIZE) && (howmuch2 > 0)); done: if (t->bytessent >= t->xpack->st_size) { #ifdef HAVE_MMAP if (t->mmap_info) { t->mmap_info->ref_count--; if (!t->mmap_info->ref_count) { int callval_i; callval_i = munmap(t->mmap_info->mmap_ptr, t->mmap_info->mmap_size); if (callval_i < 0) { outerror(OUTERROR_TYPE_WARN, "Couldn't munmap(): %s", strerror(errno)); } irlist_delete(&t->xpack->mmaps, t->mmap_info); } t->mmap_info = NULL; } #endif t->tr_status = TRANSFER_STATUS_WAITING; } return; }
int setupdccchat(const char *nick, const char *hostmask, const char *line) { char *ip, *port; SIGNEDSOCK int addrlen; int retval; dccchat_t *chat; char *msg; updatecontext(); ip = getpart(line,7); port = getpart(line,8); if ( !ip || !port ) { mydelete(ip); mydelete(port); return 1; } /* support passive dcc */ if (strcmp(port, "0") == 0) { char *token; mydelete(ip); mydelete(port); if (gdata.passive_dcc_chat) { token = getpart(line, 9); setupdccchatout(nick, hostmask, token); mydelete(token); } else { notice(nick, "DCC passive Chat denied, use \"/MSG %s ADMIN password CHATME\" instead.", get_user_nick()); ioutput(OUT_S|OUT_L|OUT_D, COLOR_MAGENTA, "DCC CHAT attempt denied from %s (%s on %s)", nick, hostmask, gnetwork->name); } return 1; } chat = irlist_add(&gdata.dccchats, sizeof(dccchat_t)); chat->name = gnetwork->name; bzero((char *) &(chat->con.remote), sizeof(chat->con.remote)); chat->con.family = (strchr(ip, ':')) ? AF_INET6 : AF_INET; chat->con.clientsocket = socket(chat->con.family, SOCK_STREAM, 0); if (chat->con.clientsocket < 0) { outerror(OUTERROR_TYPE_WARN_LOUD,"Socket Error: %s", strerror(errno)); chat->con.clientsocket = FD_UNUSED; mydelete(ip); mydelete(port); return 1; } port[strlen(port)-1] = '\0'; if (chat->con.family == AF_INET) { addrlen = sizeof(struct sockaddr_in); chat->con.remote.sin.sin_family = AF_INET; chat->con.remote.sin.sin_port = htons(atoi(port)); chat->con.remote.sin.sin_addr.s_addr = htonl(atoul(ip)); } else { addrlen = sizeof(struct sockaddr_in6); chat->con.remote.sin6.sin6_family = AF_INET6; chat->con.remote.sin6.sin6_port = htons(atoi(port)); retval = inet_pton(AF_INET6, ip, &(chat->con.remote.sin6.sin6_addr)); if (retval != 0) outerror(OUTERROR_TYPE_WARN_LOUD, "Invalid IP: %s", ip); } mydelete(port); mydelete(ip); if (is_in_badip(&(chat->con.remote))) { shutdowndccchat(chat, 0); return 1; } if (bind_irc_vhost(chat->con.family, chat->con.clientsocket) != 0) { outerror(OUTERROR_TYPE_WARN_LOUD, "Couldn't Bind To Virtual Host: %s", strerror(errno)); chat->con.clientsocket = FD_UNUSED; return 1; } if (set_socket_nonblocking(chat->con.clientsocket, 1) < 0 ) { outerror(OUTERROR_TYPE_WARN,"Couldn't Set Non-Blocking"); } alarm(CTIMEOUT); retval = connect(chat->con.clientsocket, &(chat->con.remote.sa), addrlen); if ((retval < 0) && !((errno == EINPROGRESS) || (errno == EAGAIN))) { outerror(OUTERROR_TYPE_WARN_LOUD,"Connection to DCC Chat Failed: %s", strerror(errno)); chat->con.clientsocket = FD_UNUSED; return 1; } alarm(0); addrlen = sizeof(chat->con.local); if (getsockname(chat->con.clientsocket, &(chat->con.local.sa), &addrlen) < 0) { outerror(OUTERROR_TYPE_WARN_LOUD,"Couldn't get sock name: %s", strerror(errno)); chat->con.clientsocket = FD_UNUSED; return 1; } if (gdata.debug > 0) { ioutput(OUT_S, COLOR_YELLOW, "dccchat socket = %d", chat->con.clientsocket); } gdata.num_dccchats++; chat->status = DCCCHAT_CONNECTING; chat->nick = mystrdup(nick); chat->hostmask = mystrdup(hostmask); chat->con.localport = 0; chat->con.connecttime = gdata.curtime; chat->con.lastcontact = gdata.curtime; chat->net = gnetwork->net; msg = mymalloc(maxtextlength); my_getnameinfo(msg, maxtextlength -1, &(chat->con.local.sa)); chat->con.localaddr = mystrdup(msg); my_getnameinfo(msg, maxtextlength -1, &(chat->con.remote.sa)); chat->con.remoteaddr = mystrdup(msg); mydelete(msg); ioutput(OUT_S|OUT_L|OUT_D, COLOR_MAGENTA, "DCC CHAT received from %s on %s, attempting connection to %s", nick, chat->name, chat->con.remoteaddr); return 0; }
/* accept incoming connection */ static void telnet_accept(unsigned int i) { gnetwork_t *backup; char *msg; dccchat_t *chat; SIGNEDSOCK int addrlen; updatecontext(); chat = irlist_add(&gdata.dccchats, sizeof(dccchat_t)); chat->name = "telnet"; /* NOTRANSLATE */ chat->status = DCCCHAT_UNUSED; chat->con.family = telnet_family[i]; if (chat->con.family != AF_INET) { addrlen = sizeof (struct sockaddr_in6); chat->con.clientsocket = accept(telnet_listen[i], &(chat->con.remote.sa), &addrlen); } else { addrlen = sizeof (struct sockaddr_in); chat->con.clientsocket = accept(telnet_listen[i], &(chat->con.remote.sa), &addrlen); } if (chat->con.clientsocket < 0) { outerror(OUTERROR_TYPE_WARN, "Accept Error, Aborting: %s", strerror(errno)); return; } if (set_socket_nonblocking(chat->con.clientsocket, 1) < 0 ) { outerror(OUTERROR_TYPE_WARN, "Couldn't Set Non-Blocking"); } addrlen = sizeof(chat->con.local); if (getsockname(chat->con.clientsocket, &(chat->con.local.sa), &addrlen) < 0) { outerror(OUTERROR_TYPE_WARN_LOUD, "Couldn't get sock name: %s", strerror(errno)); shutdown_close(chat->con.clientsocket); chat->con.clientsocket = FD_UNUSED; return; } ++(gdata.num_dccchats); chat->status = DCCCHAT_AUTHENTICATING; chat->net = 0; chat->nick = mystrdup("telnet"); /* NOTRANSLATE */ chat->hostmask = to_hostmask(chat->nick, "telnet"); /* NOTRANSLATE */ chat->con.localport = gdata.telnet_port; chat->con.connecttime = gdata.curtime; chat->con.lastcontact = gdata.curtime; msg = mymalloc(maxtextlength); my_getnameinfo(msg, maxtextlength -1, &(chat->con.remote.sa)); chat->con.localaddr = mystrdup(msg); my_getnameinfo(msg, maxtextlength -1, &(chat->con.local.sa)); chat->con.remoteaddr = mystrdup(msg); ioutput(OUT_S|OUT_L|OUT_D, COLOR_MAGENTA, "Telnet connection received from %s", msg); mydelete(msg); if (is_in_badip(&(chat->con.remote))) { shutdowndccchat(chat, 0); return; } if (irlist_size(&gdata.telnet_allow) > 0) { if (!verify_cidr(&gdata.telnet_allow, &(chat->con.remote))) { shutdowndccchat(chat, 0); return; } } if (verify_cidr(&gdata.telnet_deny, &(chat->con.remote))) { shutdowndccchat(chat, 0); return; } ir_boutput_init(&chat->boutput, chat->con.clientsocket, 0); backup = gnetwork; gnetwork = &(gdata.networks[chat->net]); setup_chat_banner(chat); gnetwork = backup; }
unsigned int read_statefile(void) { int fd; ir_uint32 *buffer, *buffer_begin; ir_uint32 buffer_len; struct MD5Context md5sum; MD5Digest digest; struct stat st; statefile_hdr_t *hdr; ir_uint32 calluval; unsigned int save = 0; time_t timestamp = 0; updatecontext(); if (gdata.statefile == NULL) { return save; } ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "Loading State File... "); fd = open(gdata.statefile, O_RDONLY | O_CREAT | ADDED_OPEN_FLAGS, CREAT_PERMISSIONS ); if (fd < 0) { outerror(OUTERROR_TYPE_WARN_LOUD, "Cant Access State File '%s': %s", gdata.statefile, strerror(errno)); return ++save; } if ((fstat(fd, &st) < 0) || (st.st_size < ((off_t)(sizeof(ir_uint32) * 2) + (off_t)(sizeof(MD5Digest))))) { ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "State File: Too small, Skipping"); close(fd); return ++save; } buffer_len = st.st_size; buffer_begin = buffer = mycalloc(buffer_len); calluval = read(fd, buffer, buffer_len); close(fd); if (calluval != buffer_len) { outerror(OUTERROR_TYPE_WARN_LOUD, "Cant Read State File (%u != %u) %s", calluval, buffer_len, strerror(errno)); goto error_out; } /* verify md5sum */ buffer_len -= sizeof(MD5Digest); MD5Init(&md5sum); MD5Update(&md5sum, (md5byte*)buffer, buffer_len); MD5Final(digest, &md5sum); if (memcmp(digest, buffer+(buffer_len/sizeof(ir_uint32)), sizeof(MD5Digest))) { outerror(OUTERROR_TYPE_CRASH, "\"%s\" Appears corrupt or is not an iroffer state file", gdata.statefile); goto error_out; } /* read */ if (ntohl(*buffer) != STATEFILE_MAGIC) { outerror(OUTERROR_TYPE_CRASH, "\"%s\" Does not appear to be an iroffer state file", gdata.statefile); goto error_out; } buffer++; buffer_len -= sizeof(ir_uint32); if (gdata.debug > 0) { ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, " [Version %u State File]", ntohl(*buffer)); } buffer++; buffer_len -= sizeof(ir_uint32); while ((hdr = read_statefile_item(&buffer, &buffer_len))) { switch (hdr->tag) { case STATEFILE_TAG_TIMESTAMP: read_statefile_time(hdr, "Timestamp", ×tamp, "Written on"); break; case STATEFILE_TAG_XFR_RECORD: read_statefile_float(hdr, "xfr Record", &(gdata.record), "Record"); break; case STATEFILE_TAG_SENT_RECORD: read_statefile_float(hdr, "sent Record", &(gdata.sentrecord), "Bandwidth Record"); break; case STATEFILE_TAG_TOTAL_SENT: read_statefile_llint(hdr, "Total Transferred", &(gdata.totalsent), "Total Transferred"); break; case STATEFILE_TAG_TOTAL_UPTIME: read_statefile_long(hdr, "Total Runtime", &(gdata.totaluptime)); if (gdata.debug > 0) { char *tempstr; tempstr = mymalloc(maxtextlength); getuptime(tempstr, 0, gdata.curtime-gdata.totaluptime, maxtextlength); ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, " [Total Runtime %s]", tempstr); mydelete(tempstr); } break; case STATEFILE_TAG_LAST_LOGROTATE: read_statefile_time(hdr, "Last Log Rotate", &(gdata.last_logrotate), "Last Log Rotate"); break; case STATEFILE_TAG_IROFFER_VERSION: if (hdr->length > sizeof(statefile_hdr_t)) { char *iroffer_version = (char*)(&hdr[1]); char *iroffer_now; iroffer_version[hdr->length-sizeof(statefile_hdr_t)-1] = '\0'; if (gdata.debug > 0) { ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, " [Written by %s]", iroffer_version); } iroffer_now = mycalloc(maxtextlength); snprintf(iroffer_now, maxtextlength, "iroffer-dinoex " VERSIONLONG ", %s", gdata.osstring); if (strcmp(iroffer_version, iroffer_now) != 0) { ++save; backup_statefile(); } mydelete(iroffer_now); } else { read_statefile_bad_tag(hdr, "Iroffer Version"); } break; case STATEFILE_TAG_IGNORE: { igninfo *ignore; statefile_hdr_t *ihdr; ignore = irlist_add(&gdata.ignorelist, sizeof(igninfo)); hdr->length -= sizeof(*hdr); ihdr = &hdr[1]; while (hdr->length >= sizeof(*hdr)) { ihdr->tag = ntohl(ihdr->tag); ihdr->length = ntohl(ihdr->length); switch (ihdr->tag) { case STATEFILE_TAG_IGNORE_FLAGS: read_statefile_int(ihdr, "Ignore Flags", &(ignore->flags)); break; case STATEFILE_TAG_IGNORE_BUCKET: read_statefile_long(ihdr, "Ignore Bucket", &(ignore->bucket)); break; case STATEFILE_TAG_IGNORE_LASTCONTACT: read_statefile_time(ihdr, "Ignore Lastcontact", &(ignore->lastcontact), NULL); break; case STATEFILE_TAG_IGNORE_HOSTMASK: read_statefile_string(ihdr, "Ignore Hostmask", &(ignore->hostmask)); break; default: read_statefile_unknown_tag(ihdr, "Ignore" ); } hdr->length -= ceiling(ihdr->length, 4); ihdr = (statefile_hdr_t*)(((char*)ihdr) + ceiling(ihdr->length, 4)); } if ((!ignore->lastcontact) || (!ignore->hostmask)) { read_statefile_incomplete_tag("Ignore" ); mydelete(ignore->hostmask); irlist_delete(&gdata.ignorelist, ignore); } else { ignore->bucket -= (gdata.curtime - timestamp)/gdata.autoignore_threshold; } } break; case STATEFILE_TAG_MSGLOG: { msglog_t *msglog; statefile_hdr_t *ihdr; msglog = irlist_add(&gdata.msglog, sizeof(msglog_t)); hdr->length -= sizeof(*hdr); ihdr = &hdr[1]; while (hdr->length >= sizeof(*hdr)) { ihdr->tag = ntohl(ihdr->tag); ihdr->length = ntohl(ihdr->length); switch (ihdr->tag) { case STATEFILE_TAG_MSGLOG_WHEN: read_statefile_time(ihdr, "Msglog When", &(msglog->when), NULL); break; case STATEFILE_TAG_MSGLOG_HOSTMASK: read_statefile_string(ihdr, "Msglog Hostmask", &(msglog->hostmask)); break; case STATEFILE_TAG_MSGLOG_MESSAGE: read_statefile_string(ihdr, "Msglog Message", &(msglog->message)); break; default: read_statefile_unknown_tag(ihdr, "Msglog" ); } hdr->length -= ceiling(ihdr->length, 4); ihdr = (statefile_hdr_t*)(((char*)ihdr) + ceiling(ihdr->length, 4)); } if ((!msglog->when) || (!msglog->hostmask) || (!msglog->message)) { read_statefile_incomplete_tag("Msglog" ); mydelete(msglog->hostmask); mydelete(msglog->message); irlist_delete(&gdata.msglog, msglog); } } break; case STATEFILE_TAG_XDCCS: { xdcc *xd; statefile_hdr_t *ihdr; xd = irlist_add(&gdata.xdccs, sizeof(xdcc)); xd->file_fd = FD_UNUSED; xd->minspeed = gdata.transferminspeed; xd->maxspeed = gdata.transfermaxspeed; hdr->length -= sizeof(*hdr); ihdr = &hdr[1]; while (hdr->length >= sizeof(*hdr)) { ihdr->tag = ntohl(ihdr->tag); ihdr->length = ntohl(ihdr->length); switch (ihdr->tag) { case STATEFILE_TAG_XDCCS_FILE: read_statefile_string(ihdr, "XDCC File", &(xd->file)); xd->desc = mystrdup(getfilename(xd->file)); break; case STATEFILE_TAG_XDCCS_DESC: mydelete(xd->desc); read_statefile_string(ihdr, "XDCC Desc", &(xd->desc)); break; case STATEFILE_TAG_XDCCS_NOTE: read_statefile_string(ihdr, "XDCC Note", &(xd->note)); break; case STATEFILE_TAG_XDCCS_GETS: read_statefile_int(ihdr, "XDCC Gets", &(xd->gets)); break; case STATEFILE_TAG_XDCCS_MINSPEED: read_statefile_float_set(ihdr, "XDCC Minspeed", &(xd->minspeed)); break; case STATEFILE_TAG_XDCCS_MAXSPEED: read_statefile_float_set(ihdr, "XDCC Maxspeed", &(xd->maxspeed)); break; case STATEFILE_TAG_XDCCS_MD5SUM_INFO: read_statefile_md5info(ihdr, "XDCC md5sum", xd); break; case STATEFILE_TAG_XDCCS_CRC32: read_statefile_int(ihdr, "XDCC CRC32", &(xd->crc32)); xd->has_crc32 = 1; break; case STATEFILE_TAG_XDCCS_GROUP: read_statefile_string(ihdr, "XDCC Group", &(xd->group)); break; case STATEFILE_TAG_XDCCS_GROUP_DESC: read_statefile_string(ihdr, "XDCC Group Desc", &(xd->group_desc)); break; case STATEFILE_TAG_XDCCS_LOCK: read_statefile_string(ihdr, "XDCC Lock", &(xd->lock)); break; case STATEFILE_TAG_XDCCS_DLIMIT_MAX: read_statefile_int(ihdr, "XDCC Limit Max", &(xd->dlimit_max)); break; case STATEFILE_TAG_XDCCS_DLIMIT_USED: read_statefile_int(ihdr, "XDCC Limit Used", &(xd->dlimit_used)); break; case STATEFILE_TAG_XDCCS_DLIMIT_DESC: read_statefile_string(ihdr, "XDCC Limit Desc", &(xd->dlimit_desc)); break; case STATEFILE_TAG_XDCCS_TRIGGER: read_statefile_string(ihdr, "XDCC Trigger", &(xd->trigger)); break; case STATEFILE_TAG_XDCCS_XTIME: read_statefile_time(ihdr, "XDCC Time", &(xd->xtime), NULL); break; case STATEFILE_TAG_XDCCS_COLOR: read_statefile_int(ihdr, "XDCC Color", &(xd->color)); break; default: read_statefile_unknown_tag(ihdr, "XDCC" ); } hdr->length -= ceiling(ihdr->length, 4); ihdr = (statefile_hdr_t*)(((char*)ihdr) + ceiling(ihdr->length, 4)); } if ((!xd->file) || (!xd->desc)) { read_statefile_incomplete_tag("XDCC" ); mydelete(xd->file); mydelete(xd->desc); mydelete(xd->note); mydelete(xd->group); mydelete(xd->group_desc); mydelete(xd->lock); mydelete(xd->trigger); irlist_delete(&gdata.xdccs, xd); } else { if (stat(xd->file, &st) < 0) { outerror(OUTERROR_TYPE_WARN, "Pack %u: Cant Access Offered File '%s': %s", number_of_pack(xd), xd->file, strerror(errno)); memset(&st, 0, sizeof(st)); break; } if (!xd->has_md5sum || (xd->st_ino != st.st_ino) || (xd->mtime != st.st_mtime) || (xd->st_size != st.st_size)) { xd->st_size = st.st_size; xd->st_dev = st.st_dev; xd->st_ino = st.st_ino; xd->mtime = st.st_mtime; xd->has_md5sum = 0; memset(xd->md5sum, 0, sizeof(MD5Digest)); } if (xd->st_dev != st.st_dev) { /* only mountpoint has changed */ xd->st_dev = st.st_dev; } if (xd->st_size == 0) { outerror(OUTERROR_TYPE_WARN, "Pack %u: The file \"%s\" has size of 0 byte!", number_of_pack(xd), xd->file); } if (xd->st_size > gdata.max_file_size) { outerror(OUTERROR_TYPE_CRASH, "Pack %u: The file \"%s\" is too large!", number_of_pack(xd), xd->file); } } } break; case STATEFILE_TAG_TLIMIT_DAILY_USED: read_statefile_llint(hdr, "Daily Transfer Limit Used", &(gdata.transferlimits[TRANSFERLIMIT_DAILY].used), "Daily Transfer Limit Used"); break; case STATEFILE_TAG_TLIMIT_DAILY_ENDS: read_statefile_time(hdr, "Daily Transfer Limit Ends", &(gdata.transferlimits[TRANSFERLIMIT_DAILY].ends), "Daily Transfer Limit Ends"); break; case STATEFILE_TAG_TLIMIT_WEEKLY_USED: read_statefile_llint(hdr, "Weekly Transfer Limit Used", &(gdata.transferlimits[TRANSFERLIMIT_WEEKLY].used), "Weekly Transfer Limit Used"); break; case STATEFILE_TAG_TLIMIT_WEEKLY_ENDS: read_statefile_time(hdr, "Weekly Transfer Limit Ends", &(gdata.transferlimits[TRANSFERLIMIT_WEEKLY].ends), "Weekly Transfer Limit Ends"); break; case STATEFILE_TAG_TLIMIT_MONTHLY_USED: read_statefile_llint(hdr, "Monthly Transfer Limit Used", &(gdata.transferlimits[TRANSFERLIMIT_MONTHLY].used), "Monthly Transfer Limit Used"); break; case STATEFILE_TAG_TLIMIT_MONTHLY_ENDS: read_statefile_time(hdr, "Monthly Transfer Limit Ends", &(gdata.transferlimits[TRANSFERLIMIT_MONTHLY].ends), "Monthly Transfer Limit Ends"); break; case STATEFILE_TAG_QUEUE: read_statefile_queue(hdr); break; default: read_statefile_unknown_tag(hdr, "Main" ); break; } } if (buffer_len) { outerror(OUTERROR_TYPE_WARN, "Extra data at end of state file!? %u left", buffer_len); } /* end read */ if ((gdata.debug > 0) || irlist_size(&gdata.ignorelist)) { ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, " [Found %u %s]", irlist_size(&gdata.ignorelist), (irlist_size(&gdata.ignorelist) == 1) ? "ignore" : "ignores"); } if ((gdata.debug > 0) || irlist_size(&gdata.msglog)) { ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, " [Found %u %s]", irlist_size(&gdata.msglog), (irlist_size(&gdata.msglog) == 1) ? "message" : "messages"); } if ((gdata.debug > 0) || irlist_size(&gdata.xdccs)) { ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, " [Found %u %s]", irlist_size(&gdata.xdccs), (irlist_size(&gdata.xdccs) == 1) ? "pack" : "packs"); } if ((gdata.debug > 0) || irlist_size(&gdata.mainqueue)) { ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, " [Found %u %s]", irlist_size(&gdata.mainqueue), (irlist_size(&gdata.mainqueue) == 1) ? "queue" : "queues"); } if ((gdata.debug > 0) || irlist_size(&gdata.idlequeue)) { ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, " [Found %u %s]", irlist_size(&gdata.idlequeue), (irlist_size(&gdata.idlequeue) == 1) ? "queue" : "queues"); } ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, " [Done]"); error_out: mydelete(buffer_begin); return save; }