/* dcc shtuff */ #include #include #include #include #include #include #include #include /* hpux needs for ntohl */ #include "eggdrop.h" extern int serv; extern int require_x; extern struct dcc_t dcc[]; extern int dcc_total; extern char dccin[]; extern int conmask; extern char botname[]; extern char origbotname[]; extern int isolate; extern int require_p; extern char dccdir[]; extern int flood_thr; extern int upload_to_cd; extern char tempdir[]; extern int bitch; /* received a ctcp-dcc */ void gotdcc(nick,from,msg) char *nick,*from,*msg; { char code[512],param[512],s[256],s1[81],prt[81]; int z,i,atr; FILE *f; nsplit(code,msg); if ((strcasecmp(code,"chat")!=0) && (strcasecmp(code,"send")!=0)) return; /* dcc chat or send! */ nsplit(param,msg); nsplit(s,msg); nsplit(prt,msg); sprintf(s1,"%s!%s",nick,from); atr=get_attr_host(s1); if (strcasecmp(code,"chat")==0) { int ok=0; char nk[40]; if ((!require_p) || (!require_x)) if (atr & USER_OP) ok=1; if (atr & (USER_MASTER|USER_XFER|USER_PARTY)) ok=1; if (!ok) { mprintf(serv,"NOTICE %s :No access.\n",nick); log(LOG_MISC,"Refused DCC chat (no access): %s!%s",nick,from); return; } else { if (atr&USER_TANDEM) { get_handle_by_host(nk,s1); if (in_chain(nk)) { mprintf(serv,"NOTICE %s :You're already connected.\n",nick); log(LOG_TAND,"Refused tandem connection from %s (duplicate)",nk); return; } } } } if (strcasecmp(code,"send")==0) { int ok=0; if (!require_x) if (atr & USER_OP) ok=1; if (atr & (USER_MASTER|USER_XFER)) ok=1; if (!ok) { mprintf(serv,"NOTICE %s :No file transfer access.\n",nick); log(LOG_MISC,"Refused DCC SEND %s (no access): %s!%s",param,nick,from); return; } } if (dcc_total==MAXDCC) { mprintf(serv,"NOTICE %s :Sorry, too many DCC connections.\n",nick); log(LOG_MISC,"DCC connections full: %s %s (%s!%s)",code,param,nick,from); return; } if ((dccin[0]==0) && (!upload_to_cd) && (strcasecmp(code,"send")==0)) { mprintf(serv,"NOTICE %s :DCC file transfers not supported.\n",nick); log(LOG_MISC,"Refused dcc send %s from %s!%s",param,nick,from); return; } if ((strchr(param,'/')!=NULL) && (strcasecmp(code,"send")==0)) { mprintf(serv,"NOTICE %s :Filename cannot have '/' in it...\n",nick); log(LOG_MISC,"Refused dcc send %s from %s!%s",param,nick,from); return; } i=dcc_total; dcc[i].addr=atol(s); dcc[i].port=atoi(prt); dcc[i].sock=(-1); dcc[i].type=DCC_FORK; strcpy(dcc[i].nick,nick); strcpy(dcc[i].host,from); dcc[i].u.other=NULL; set_fork(i); if (strcasecmp(code,"send")==0) { char nk[40],s9[121]; get_xfer_ptr(&(dcc[i].u.fork->u.xfer)); if (param[0]=='.') param[0]='_'; strcpy(dcc[i].u.fork->u.xfer->filename,param); if (upload_to_cd) { get_handle_by_host(nk,s1); get_handle_dccdir(nk,s9); sprintf(dcc[i].u.fork->u.xfer->dir,"%s%s/",dccdir,s9); } else strcpy(dcc[i].u.fork->u.xfer->dir,dccin); dcc[i].u.fork->u.xfer->length=atol(msg); dcc[i].u.fork->u.xfer->sent=0; dcc[i].u.fork->u.xfer->sofar=0; } else { get_chat_ptr(&(dcc[i].u.fork->u.chat)); dcc[i].u.fork->u.chat->away=NULL; dcc[i].u.fork->u.chat->status=0; dcc[i].u.fork->u.chat->timer=time(NULL); dcc[i].u.fork->u.chat->msgs_per_sec=0; dcc[i].u.fork->u.chat->con_flags=0; dcc[i].u.fork->u.chat->channel=0; } if (strcasecmp(code,"chat")==0) { if (atr & USER_MASTER) { z=DCC_CHAT; dcc[i].u.fork->u.chat->status|=STAT_MASTER; } else if (atr & USER_OP) { if ((!require_p) || (atr & USER_PARTY)) z=DCC_CHAT; else if ((!require_x) || (atr & USER_XFER)) z=DCC_FILES; else { mprintf(serv,"NOTICE %s :No access.\n",nick); log(LOG_MISC,"Refused dcc chat (no access): %s!%s",nick,from); return; } } else if (atr & USER_PARTY) { z=DCC_CHAT; dcc[i].u.fork->u.chat->status|=STAT_PARTY; } else if (atr & USER_XFER) { z=DCC_FILES; } else { mprintf(serv,"NOTICE %s :No access.\n",nick); log(LOG_MISC,"Refused dcc chat (no access): %s!%s",nick,from); return; } if (atr & USER_XFER) dcc[i].u.fork->u.chat->status|=STAT_XFER; if (bitch && (pass_match_by_host("nopass",s1))) { mprintf(serv,"NOTICE %s :You must have a password set.\n",nick); log(LOG_MISC,"Refused dcc chat (no password): %s!%s",nick,from); return; } if (z==DCC_FILES) { /* ARGH: three level nesting */ struct file_info *fi; get_file_ptr(&fi); fi->chat=dcc[i].u.fork->u.chat; dcc[i].u.fork->u.file=fi; } } else { z=DCC_SEND; sprintf(s1,"%s%s",dcc[i].u.fork->u.xfer->dir,param); f=fopen(s1,"r"); if (f!=NULL) { fclose(f); mprintf(serv,"NOTICE %s :That file already exists.\n",nick); nfree(dcc[i].u.xfer); return; } /* put uploads in /tmp first */ sprintf(s1,"%s%s",tempdir,param); f=fopen(s1,"w"); if (f==NULL) { mprintf(serv,"NOTICE %s :Can't create that file.\n",nick); nfree(dcc[i].u.xfer); return; } fclose(f); } dcc[i].u.fork->type=z; /* store future type */ dcc_total++; /* ok, we're satisfied with them now: fork out and telnet to them */ fork_telnet_dcc(i,s,prt); } void cont_got_dcc(z,idx) int z,idx; { char s1[121]; if (z>0) { errno=z; neterror(s1); if (z==-2) strcpy(s1,"Can't find hostname lookup"); if (z==-3) strcpy(s1,"Fake hostname -- not even trying"); mprintf(serv,"NOTICE %s :Failed to connect (%s)\n",dcc[idx].nick,s1); log(LOG_MISC,"DCC connection failed: %s %s (%s!%s)", dcc[idx].u.fork->type==DCC_SEND?"SEND":"CHAT",dcc[idx].u.fork->type ==DCC_SEND?dcc[idx].u.fork->u.xfer->filename:"",dcc[idx].nick, dcc[idx].host); log(LOG_MISC," (%s)",s1); if (dcc[idx].u.fork->type==DCC_SEND) { /* erase the 0-byte file i started */ sprintf(s1,"%s%s",tempdir,dcc[idx].u.fork->u.xfer->filename); unlink(s1); } dcc[idx].sock=dcc[idx].type; dcc[idx].type=DCC_LOST; return; } sprintf(s1,"%s!%s",dcc[idx].nick,dcc[idx].host); z=dcc[idx].sock; dcc[idx].type=dcc[idx].u.fork->type; { /* cut out the fork part of the chain */ struct fork_info *fi=dcc[idx].u.fork; dcc[idx].u.other=fi->u.other; nfree(fi); } log(LOG_MISC,"DCC connection: %s %s (%s)",dcc[idx].type==DCC_SEND?"SEND": "CHAT",dcc[idx].type==DCC_SEND?dcc[idx].u.xfer->filename:"",s1); if (dcc[idx].type!=DCC_SEND) { get_handle_by_host(dcc[idx].nick,s1); dcc[idx].u.chat->timer=time(NULL); if (pass_match_by_host("nopass",s1)) { /* no password set */ tprintf(z,"( YOU HAVE NO PASSWORD SET )\n"); if (dcc[idx].type==DCC_CHAT) { if (dcc[idx].u.chat->status&STAT_MASTER) dcc[idx].u.chat->con_flags=conmask; dcc_chatter(z); } else { welcome_to_files(idx,z); log(LOG_MISC,"File system: [%s]%s/%d",dcc[idx].nick,dcc[idx].host, dcc[idx].port); } } else { tprintf(z,"Enter your password.\n"); if (dcc[idx].type==DCC_CHAT) dcc[idx].type=DCC_CHAT_PASS; else dcc[idx].type=DCC_FILES_PASS; } } } /* return code: 0: okay 1: dcc table full 2: can't open listening socket 3: no such file */ int raw_dcc_send(filename,nick) char *filename,*nick; { int zz,port=0,i; char *p,*nfn; unsigned long host; struct stat ss; FILE *f; f=fopen(filename,"r"); if (f==NULL) return 3; else fclose(f); if (dcc_total==MAXDCC) return 1; zz=open_listen(&port); if (zz==(-1)) return 2; nfn=strrchr(filename,'/'); if (nfn==NULL) nfn=filename; else nfn++; host=getmyip(); stat(filename,&ss); i=dcc_total; dcc[i].sock=zz; dcc[i].addr=(unsigned int)(-559026163); dcc[i].port=port; strcpy(dcc[i].nick,nick); strcpy(dcc[i].host,"irc"); dcc[i].type=DCC_GET_PENDING; set_xfer(i); strcpy(dcc[i].u.xfer->filename,filename); dcc[i].u.xfer->length=ss.st_size; dcc[i].u.xfer->sent=0; dcc[i].u.xfer->sofar=0; dcc[i].u.xfer->pending=time(NULL); dcc_total++; mprintf(serv,"PRIVMSG %s :%cDCC SEND %s %lu %d %lu%c\n",nick,1,nfn,host, port,ss.st_size,1); log(LOG_MISC,"Begin DCC send %s to %s",nfn,nick); return 0; } int dcc_send(idx,z,filename,nick) int idx,z; char *filename,*nick; { int x; char *nfn; x=raw_dcc_send(filename,nick); if (x==1) { tprintf(z,"Sorry, too many DCC connections.\n"); log(LOG_MISC,"DCC connections full: GET %s [%s]",filename,dcc[idx].nick); return 0; } if (x==2) { tprintf(z,"Unable to listen at a socket.\n"); log(LOG_MISC,"DCC socket error: GET %s [%s]",filename,dcc[idx].nick); return 0; } nfn=strrchr(filename,'/'); if (nfn==NULL) nfn=filename; else nfn++; if (strcasecmp(nick,dcc[idx].nick)!=0) mprintf(serv,"NOTICE %s :Here is a file from %s ...\n",nick,dcc[idx].nick); tprintf(z,"Type '/DCC GET %s %s' to receive.\n",botname,nfn); tprintf(z,"DCC sending '%s' to %s...\n",nfn,nick); return 1; } int do_dcc_send(idx,z,dir,filename) int idx,z; char *dir,*filename; { char s[121],fn[256],nick[256]; FILE *f; /* nickname? */ strcpy(nick,filename); nsplit(fn,nick); if (dccdir[0]==0) { tprintf(z,"DCC file transfers not supported.\n"); log(LOG_MISC,"Refused dcc get %s from [%s]",fn,dcc[idx].nick); return 0; } if (strchr(fn,'/')!=NULL) { tprintf(z,"Filename cannot have '/' in it...\n"); log(LOG_MISC,"Refused dcc get %s from [%s]",fn,dcc[idx].nick); return 0; } if (dir[0]) sprintf(s,"%s%s/%s",dccdir,dir,fn); else sprintf(s,"%s%s",dccdir,fn); f=fopen(s,"r"); if (f==NULL) { tprintf(z,"No such file.\n"); log(LOG_MISC,"Refused dcc get %s from [%s]",fn,dcc[idx].nick); return 0; } fclose(f); /* copy this file to /tmp */ if (dir[0]) sprintf(s,"cp %s%s/%s %s%s",dccdir,dir,fn,tempdir,fn); else sprintf(s,"cp %s%s %s%s",dccdir,fn,tempdir,fn); system(s); sprintf(s,"%s%s",tempdir,fn); if (!nick[0]) strcpy(nick,dcc[idx].nick); return dcc_send(idx,z,s,nick); } int detect_dcc_flood(chat,idx) struct chat_info *chat; int idx; { int i; time_t t; t=time(NULL); if (chat->timer!=t) { chat->timer=t; chat->msgs_per_sec=0; } else { chat->msgs_per_sec++; if (chat->msgs_per_sec > flood_thr) { /* FLOOD */ tprintf(dcc[idx].sock,"*** FLOOD: Goodbye.\n"); if (dcc[idx].u.chat->channel>=0) { chanout_but(idx,dcc[idx].u.chat->channel, "*** %s forcibly removed from the bot for %s\n", dcc[idx].nick,"flooding."); if (!isolate) tandout("chan %s %d %s booted for flooding.\n",origbotname, dcc[idx].u.chat->channel,dcc[idx].nick); } if (dcc[idx].sock!=STDOUT) { close(dcc[idx].sock); shutdown(dcc[idx].sock,2); lostdcc(idx); } else { tprintf(STDOUT,"\n### SIMULATION RESET ###\n\n"); dcc_chatter(STDOUT); } return 1; /* <- flood */ } } return 0; } /* given idx of a completed file operation, check to make sure no other file transfers are happening currently on that file -- if there aren't any, erase the file (it's just a copy anyway) */ void wipe_tmp_file(idx) int idx; { int i,ok=1; for (i=0; ifilename,dcc[idx].u.xfer->filename)==0) ok=0; if (ok) unlink(dcc[idx].u.xfer->filename); }