/* process handling for eggdrop 13jun94 children are split off to: accept dcc connections (which is like telnetting) telnet (link) to other bots telnet (relay) users to other bots execute system shell commands */ #include #include #include #include #include #include "eggdrop.h" extern struct dcc_t dcc[]; extern int dcc_total; extern char origbotname[]; extern char cx_file[]; extern int cx_line; #ifndef WEXITSTATUS #define WEXITSTATUS(x) ((x).w_status >> 8) #endif struct proc_t { unsigned int pid; unsigned char type; unsigned int sock; long num; /* misc */ time_t ts; struct proc_t *next; } *proc=NULL; /* valid process types: */ #define P_DCC 1 #define P_LINK 2 #define P_RELAY 3 #define P_EXEC 4 int expmem_proc() { int tot; struct proc_t *p; tot=0; p=proc; while (p!=NULL) { tot+=sizeof(struct proc_t); p=p->next; } return tot; } void new_proc(pid,type,sock,num) int pid,type,sock,num; { struct proc_t *p; p=proc; proc=(struct proc_t *)nmalloc(sizeof(struct proc_t)); proc->next=p; proc->pid=pid; proc->type=type; proc->num=num; proc->ts=time(NULL); proc->sock=sock; } void rem_proc(pid) int pid; { struct proc_t *p,*pr; if (proc==NULL) return; if (proc->pid==pid) { p=proc; proc=proc->next; nfree(p); return; } p=proc; pr=proc; while ((p!=NULL) && (p->pid!=pid)) { pr=p; p=p->next; } if (p==NULL) return; pr->next=p->next; nfree(p); } struct proc_t *find_proc(pid) int pid; { struct proc_t *p; if (proc==NULL) return proc; p=proc; while (p!=NULL) { if (p->pid==pid) return p; p=p->next; } return NULL; } int get_forked_idx(pid) int pid; { int i; for (i=0; ipid==pid)) return i; return -1; } void tell_dcc_proc(z,idx) int z,idx; { struct proc_t *p; time_t tt; int x; char s[20],s1[20]; p=find_proc(dcc[idx].u.fork->pid); if (p==NULL) { tprintf(z," (NO PROCESS RECORD!)\n"); return; } tt=time(NULL); x=(tt-(p->ts)); if (x<60) sprintf(s,"%ds",x); else sprintf(s,"%dm%ds",(x/60),(x%60)); switch (dcc[idx].u.fork->type) { case DCC_CHAT: strcpy(s1,"chat"); break; case DCC_FILES: strcpy(s1,"chat/files"); break; case DCC_TANDEM: strcpy(s1,"tandem-bot"); break; case DCC_RELAY: strcpy(s1,"relay"); break; case DCC_SEND: strcpy(s1,"file-xfer"); break; } tprintf(z," (attempting %s: process id #%d, socket %d, active %s)\n", s1,p->pid,p->sock,s); } void check_expired_forks() { struct proc_t *p; int i,ok; time_t now=time(NULL); char t[20]; p=proc; while (p!=NULL) { if (now - p->ts > 600) { /* 10 mins */ i=get_forked_idx(p->pid); if (i<0) { log(LOG_MISC,"Expired fork: process #%d (NO DCC ENTRY!)",p->pid); } else { switch(dcc[i].u.fork->type) { case DCC_CHAT: strcpy(t,"CHAT"); break; case DCC_FILES: strcpy(t,"FILES"); break; case DCC_TANDEM: strcpy(t,"TANDEM"); break; case DCC_RELAY: strcpy(t,"RELAY"); break; case DCC_SEND: strcpy(t,"SEND"); break; default: sprintf(t,"UNKNOWN %d",dcc[i].u.fork->type); break; } log(LOG_MISC,"Expired fork: process #%d (type %s to %s)",p->pid, t,dcc[i].nick); if (dcc[i].u.fork->type==DCC_TANDEM) tandout("*trying %s %s\n", origbotname,dcc[i].nick); close(p->sock); shutdown(p->sock,2); lostdcc(i); } kill(p->pid,9); rem_proc(p->pid); p=proc; } else p=p->next; } } /* stop any auto-connect processes to this bot */ void stop_auto(who) char *who; { struct proc_t *p; int i; p=proc; while (p!=NULL) { i=get_forked_idx(p->pid); if (i>=0) { if (strcasecmp(dcc[i].nick,who)==0) { close(p->sock); shutdown(p->sock,2); lostdcc(i); kill(p->pid,9); rem_proc(p->pid); p=proc; } else p=p->next; } else p=p->next; } } int procs() { struct proc_t *p; int i=0; if (proc==NULL) return 0; p=proc; while (p!=NULL) { i++; p=p->next; } return i; } /* remove all signal handlers from a child process */ void banna(sock) int sock; { struct sigaction sv; int i; for (i=0; i=0) exit(0); else exit(errno); } else if (x<0) { log(LOG_MISC,"Forking error!"); return; } else { /* parent */ dcc[idx].u.fork->pid=x; new_proc(x,P_DCC,sk,0); } } void fork_link(addr,port,idx,stport) char *addr; int port,idx,stport; { int sk,x,z; struct proc_t *p; char s[21]; sk=getsock(); x=fork(); if (x==0) { /* child */ banna(sk); z=open_telnet_raw(sk,addr,port); if (z>=0) exit(0); else exit(errno); } else if (x<0) { log(LOG_MISC,"Forking error!"); return; } else { /* parent */ dcc[idx].u.fork->pid=x; new_proc(x,P_LINK,sk,stport); } } void fork_relay(addr,port,idx,stport,uidx) char *addr; int port,idx,stport,uidx; { int sk,x,z; struct proc_t *p; char s[21]; sk=getsock(); x=fork(); if (x==0) { /* child */ banna(sk); z=open_telnet_raw(sk,addr,port); if (z>=0) exit(0); else exit(errno); } else if (x<0) { log(LOG_MISC,"Forking error!"); return; } else { /* parent */ dcc[idx].u.fork->pid=x; dcc[uidx].u.fork->pid=x; dcc[idx].u.fork->x=0; dcc[uidx].u.fork->x=1; new_proc(x,P_RELAY,sk,stport); } } /******/ extern int errno; void fork_exec(cmd,idx) char *cmd; int idx; { int sk,x,z,pp[2]; struct proc_t *p; sk=getsock(); z=dcc[idx].sock; x=fork(); if (x==0) { /* child */ banna(sk); /* point stdin/stdout/stderr to this socket: */ tprintf(STDOUT,"socket: %d\n",z); if (dup2(z,0) < 0) tprintf(STDOUT,"error!\n"); else tprintf(STDOUT,"ok\n"); tprintf(STDOUT,"error #%d\n",errno); dup2(z,1); dup2(z,2); system(cmd); exit(0); } else if (x<0) { log(LOG_MISC,"Forking error!"); return; } else { /* parent */ dcc[idx].u.fork->pid=x; new_proc(x,P_EXEC,z,0); } } /* i=pid, st=status */ void got_dead_child2(i,st) int i; WAIT_T st; { int j,idx,idx2; struct proc_t *p; context; p=find_proc(i); if (p==NULL) { log(LOG_MISC,"* Child #%d terminated without a child record!",i); log(LOG_MISC,"* Process table follows:"); p=proc; while (p!=NULL) { log(LOG_MISC,"* PID %5d TYPE %-4s SOCK %2d",p->pid,p->type== P_DCC?"dcc":(p->type==P_LINK?"link":(p->type==P_RELAY?"rlay": "exec"))); p=p->next; } log(LOG_MISC,"* (End of process table debug dump)"); return; } if ((WEXITSTATUS(st)>0) && (p->type!=P_EXEC)) { close(p->sock); shutdown(p->sock,2); } if (p->type==P_DCC) { idx=get_forked_idx(i); if (WEXITSTATUS(st)==0) dcc[idx].sock=p->sock; cont_got_dcc(WEXITSTATUS(st),idx); rem_proc(i); } else if (p->type==P_LINK) { idx=get_forked_idx(i); if (WEXITSTATUS(st)==0) dcc[idx].sock=p->sock; cont_tandem_link(WEXITSTATUS(st),idx,p->num); rem_proc(i); } else if (p->type==P_RELAY) { idx=get_forked_idx(i); if (dcc[idx].u.fork->x==1) { idx2=idx; dcc[idx2].u.fork->pid=0; idx=get_forked_idx(i); } else { dcc[idx].u.fork->pid=0; idx2=get_forked_idx(i); } if (WEXITSTATUS(st)==0) dcc[idx].sock=p->sock; cont_tandem_relay(WEXITSTATUS(st),idx,p->num,idx2); rem_proc(i); } else if (p->type==P_EXEC) { struct chat_info *ci; idx=get_forked_idx(i); ci=dcc[idx].u.fork->u.chat; nfree(dcc[idx].u.fork); dcc[idx].u.chat=ci; dcc[idx].type=DCC_CHAT; chatout("*** %s joined the party line.\n",dcc[idx].nick); tandout("chat %s %s joined the party line.\n",origbotname,dcc[idx].nick); rem_proc(i); } else { log(LOG_MISC,"* Child #%d terminated and was not trapped! (type=%d)",i, p->type); rem_proc(i); } } /* sigchild received */ void got_dead_child() { WAIT_T st; int i; i=(-1); while (i<0) { i=wait(&st); /* keep calling if interrupted by signal */ if ((i==-1) && (errno==ECHILD)) return; } got_dead_child2(i,st); }