#include #include #include #include #include #include #include #include #include #include #include #include "libirc/irc.h" //epoch's libirc. should be included with segfault. #include "libhashtable/hashtable.h" //epoch's also. //might want to change some of these. #define TSIZE 65535 #define SERVER "127.0.0.1" #define PORT "6667" #define NICK "SegFault" //override with argv[1] #define MYUSER "segfault" #define LINES_SENT_LIMIT 1 #define LINELEN 400 #define SEGHOMELEN 1024 #define RAWLOG "./files/rawlog" #define LOG "./files/log" #define MAXTAILS maxtails //just to have it more than the system default. #define BS 4096 // !c uses 56 for its tail. // 56 == 32 + 16 + 8 == 0x38 == 0x20+0x10+0x8 == SPAM | BEGIN | MSG #define TAILO_RAW 1 // r output gets sent directly to server #define TAILO_EVAL 2 // e interpret the lines read from the tail as if they were messages to segfault #define TAILO_CLOSE 4 // c close the file at EOF, default is to leave it open. #define TAILO_MSG 8 // m output gets sent as a PM to the place the tail was made. #define TAILO_BEGIN 16 // b start the tail at the beginning of the file instead of the end. #define TAILO_SPAM 32 // s Spam control is enabled for this stream. #define TAILO_ENDMSG 64 // n show a message when the tail reaches the end of a chunk #define TAILO_FORMAT 128// f formatting? #define TAILO_Q_EVAL (TAILO_EVAL|TAILO_CLOSE|TAILO_BEGIN) //0x2+0x4+0x10 = 2+4+16 = 22 #define TAILO_Q_COUT (TAILO_SPAM|TAILO_BEGIN|TAILO_MSG) //0x20+0x10+0x8 = 32+16+8 = 56 //this function isn't with the rest of them because... meh. char *tailmode_to_txt(unsigned short mode) { char *modes="recmbsn"; int i,j=0; char *m=malloc(strlen(modes)); for(i=0;inick: ((fmt[i]=='u')?user->user: ((fmt[i]=='~')?getcwd(seghome,SEGHOMELEN): ((fmt[i]=='h')?user->host: ((fmt[i]=='f')?from: ((fmt[i]=='p')?pid: ((fmt[i]=='m')?myuser->nick://and here. ((fmt[i]=='s')?arg:"%" )))))))); fmt[i-1]=0; notargs[c]=strdup(fmt+j); sz+=strlen(args[c]); sz+=strlen(notargs[c]); c++; j=i+1; } } } notargs[c]=strdup(fmt+j); sz+=strlen(notargs[c]); output=malloc(sz+1); output[0]=0; for(i=0;i 0);//this is used on named pipes usually. } } void eofp(FILE *fp) { if(fseek(fp,0,SEEK_END) == -1) { while(fgetc(fp) != -1);//this is used on named pipes usually. } clearerr(fp); } //this function got scary. basically handles all the tail magic. void extra_handler(int fd) { int tmpo,i; static int mmerp=0; char tmp[BS+1]; char *tmp2; if(oldtime == time(0) && lines_sent > LINES_SENT_LIMIT) {//if it is still the same second, skip this function. return; } else { lines_sent=0; } if(redirect_to_fd != -1) { fd=redirect_to_fd; } for(i=0;i_> if(tailf[i].lines != 0 && (tailf[i].opt & TAILO_ENDMSG)) { privmsg(fd,tailf[i].to,"---------- TAILO_ENDMSG border ----------"); } //snprintf(tmp2,sizeof(tmp)-1,"tailf[%d] (%s): errno: %d, ferror: %d",i,tailf[i].file,errno,ferror(tailf[i].fp)); //privmsg(fd,tailf[i].to,tmp2); tailf[i].lines=0; } else { tailf[i].lines++; mmerp=0; if(strchr(tmp,'\r')) *strchr(tmp,'\r')=0; if(strchr(tmp,'\n')) *strchr(tmp,'\n')=0; if(tailf[i].opt & TAILO_EVAL) {//eval if(tailf[i].opt & TAILO_FORMAT) { tmp2=format_magic(fd,tailf[i].to,tailf[i].user,tmp,tailf[i].args); } else { tmp2=strdup(tmp); } message_handler(fd,tailf[i].to,tailf[i].user,tmp2,0); free(tmp2); } if(tailf[i].opt & TAILO_RAW) {//raw tmp2=malloc(strlen(tmp)+4); snprintf(tmp2,strlen(tmp)+3,"%s\r\n",tmp); mywrite(fd,tmp2); free(tmp2); } if(tailf[i].opt & TAILO_MSG) {//just msg the lines. privmsg(fd,tailf[i].to,tmp); } if(tailf[i].lines >= line_limit && (tailf[i].opt & TAILO_SPAM)) { tailf[i].lines=-1; //lock it. privmsg(fd,tailf[i].to,"--more--"); } } } else { //don't PM in here. shows a LOT of shit. } } } } void file_tail(int fd,char *from,char *file,char *args,char opt,struct user *user) { int i; int fdd; char tmp[256]; struct stat st; for(i=0;inick=strdup(user->nick); tailf[i].user->user=strdup(user->user); tailf[i].user->host=strdup(user->host); if(!tailf[i].user) { mywrite(fd,"QUIT :malloc error 4.5!!! (a strdup again)\r\n"); return; } tailf[i].args=args?strdup(args):0; if(args) { if(!tailf[i].args) { mywrite(fd,"QUIT :malloc error 5!!! (well, strdup)\r\n"); return; } } tailf[i].lines=0; } } void c_botup(int fd,char *from,...) { char tmp[256]; snprintf(tmp,sizeof(tmp)-1,"botup: %lu",(unsigned long int)time(0)-start_time); privmsg(fd,from,tmp); } void c_leettail(int fd,char *from,char *file,struct user *user,...) { short a=file[0]-'0'; short b=file[1]-'0'; short c=file[2]-'0'; short d; short n; if(file[2] >= '0' && file[2] <= '9') { d=(a*100)+(b*10)+(c); n=3; } else { d=(a*10)+(b); n=2; } char *args; if(file[0]==' ') file++; if((args=strchr(file,' '))) { *args=0; args++; } file_tail(fd,from,file+n,args,d,user); } void c_changetail(int fd,char *from,char *line,struct user *user,...) { struct stat st; char *merp=0; char tmp[512]; int i; int fdd; char *mode=0; //if(line == 0) return mywrite(fd,"QUIT :line == 0 in changetail\r\n"); //if(from == 0) return mywrite(fd,"QUIT :from == 0 in changetail\r\n"); if((merp=strchr(line,' '))) { *merp=0; merp++; if((mode=strchr(merp,' '))) { *mode=0; mode++; } } if((fdd=open(line,O_RDONLY|O_NONBLOCK,0)) == -1) { snprintf(tmp,sizeof(tmp)-1,"%s: (%s) fd:%d",strerror(errno),line,fdd); privmsg(fd,"#cmd",tmp); return; } if(debug) { snprintf(tmp,sizeof(tmp)-1,"changetail opened file '%s' with fd: %d / %d\n",line,fdd,maxtails); privmsg(fd,"#cmd",tmp); } fstat(fdd,&st); close(fdd); for(i=0;ill;m;m=m->next) { if(strcasestr(m->original,line) || *line=='*') { snprintf(tmp,sizeof(tmp)-1," %s -> %p",m->original,m->target); privmsg(fd,from,tmp); j++; } k++; } } snprintf(tmp,sizeof(tmp)-1,"found %d of %d in builtins",j,k); privmsg(fd,from,tmp); } void c_amnesia(int fd,char *from,char *line,...) {//forget aliases ht_freevalues(&alias); ht_destroy(&alias); inittable(&alias,TSIZE); //put this as a builtin I guess. } void c_lobotomy(int fd,char *from,char *line,...) {//forget builtins ht_destroy(&builtin); inittable(&builtin,TSIZE); //don't put this as a builtin by default. :P gotta hack that out. } void c_aliases_h(int fd,char *from,char *line,...) { char tmp[512]; struct entry *m; int i,j=0,k=0; if(!line){ privmsg(fd,from,"usage: !aliases [search-term]"); return; } for(i=0;ikeys[i]); //privmsg(fd,from,tmp); for(m=alias.bucket[alias.keys[i]]->ll;m;m=m->next) { if(strcasestr(m->target,line) || strcasestr(m->original,line)) { snprintf(tmp,sizeof(tmp)-1," %s -> %s",m->original,(char *)m->target); privmsg(fd,from,tmp); j++; } k++; } } snprintf(tmp,sizeof(tmp)-1,"found %d of %d aliases",j,k); privmsg(fd,from,tmp); } void c_alias_h(int fd,char *from,char *line,...) { char tmps[512]; char *derp=strchr(line,' '); struct entry *tmp; if(!derp) { if((tmp=ht_getnode(&alias,line)) != NULL) { snprintf(tmps,sizeof(tmps)," %s",(char *)tmp->target); privmsg(fd,from,tmps); } else { snprintf(tmps,sizeof(tmps),"'%s' not an alias.",line); privmsg(fd,from,tmps); } return; } *derp=0; derp++; if((tmp=ht_getnode(&alias,line))) { free(tmp->target); } ht_setkey(&alias,line,strdup(derp)); } void c_kill(int fd,char *from,char *line,...) { char *csig=line; char *cpid=strchr(line,' '); int sig,pid; if(cpid) { *cpid=0; cpid++; } else { privmsg(fd,from,"usage: !kill signum pid"); return; } sig=atoi(csig); pid=atoi(cpid); if(sig && pid) { if(kill(pid,sig)) privmsg(fd,from,"kill error"); else privmsg(fd,from,"signal sent"); } else { privmsg(fd,from,"pid or sig is 0. something is odd."); } } void c_id(int fd,char *from,...) { char tmp[512]; snprintf(tmp,sizeof(tmp)-1,"u:%d g:%d eu:%d eg:%d",getuid(),getgid(),geteuid(),getegid()); privmsg(fd,from,tmp); } void c_leetuntail(int fd,char *from,char *line,...) { char *frm=line; char *file=0; int frmN=0; int i; char tmp[512]; if((file=strchr(line,' '))) { *file=0; file++; } if(file) { if(*frm == '*') { for(i=0;i IRCdestination"); for(i=0;i %s",tailf[i].file,tailf[i].inode,ftell(tailf[i].fp),tailf[i].lines,x,tailf[i].opt,tailf[i].to); free(x); privmsg(fd,from,tmp); free(tmp); } } if(!at_least_one) { privmsg(fd,from,"I don't have any tails. :("); } } char recording,recording_raw; void c_record(int fd,char *from,char *line,...) { if(*line == '0') { privmsg(fd,from,"no longer recording IRC."); recording=0; return; } if(*line == '1') { recording=1; unlink(LOG); privmsg(fd,from,"recording IRC."); return; } privmsg(fd,from,recording?"1":"0"); } void c_rawrecord(int fd,char *from,char *line,...) { if(!line) { printf("that's odd.\n"); return; } if(*line == '0') { privmsg(fd,from,"no longer recording raw IRC."); recording_raw=0; return; } if(*line == '1') { recording_raw=1; unlink(RAWLOG); privmsg(fd,from,"recording raw IRC."); return; } privmsg(fd,from,recording_raw?"1":"0"); } void c_leetsetout(int fd,char *from,char *msg,...) { char tmp[512]; if(redirect_to_fd != -1) close(redirect_to_fd); redirect_to_fd=open(msg+3,((msg[0]-'0')*100) + ((msg[1]-'0')*10) + (msg[2]-'0'),022); if(redirect_to_fd == -1) { snprintf(tmp,sizeof(tmp)-1,"%s: (%s) fd:%d",strerror(errno),msg+3,redirect_to_fd); privmsg(fd,"#cmd",tmp); return; } if(debug) { snprintf(tmp,sizeof(tmp)-1,"leetsetout opened file '%s' with fd: %d / %d\n",msg+3,redirect_to_fd,maxtails); privmsg(fd,"#cmd",tmp); } } void c_linelimit(int fd,char *from,char *msg,...) { char tmp[256]; if(!msg) { snprintf(tmp,255,"current spam line limit: %d (debug: %d)",line_limit,debug); privmsg(fd,from,tmp); } else { if(msg[0] == 'a') { mode_magic^=1; privmsg(fd,from,"mode_magic flipped. happy easter!"); } if(msg[0]=='!') { if(msg[1]) { trigger_char=msg[1]; privmsg(fd,from,"trigger_char set. more easter!"); } } if(atoi(msg) > 0) { line_limit=atoi(msg); snprintf(tmp,255,"spam line limit set to: %d",line_limit); privmsg(fd,from,tmp); } else if(atoi(msg) < 0) { privmsg(fd,from,"hidden feature! negative line limit flips debug bit."); debug^=1; } else { privmsg(fd,from,"something else!"); } } } void c_resetout(int fd,char *from,...) { redirect_to_fd=-1; privmsg(fd,from,"output reset"); } void c_raw(int fd,char *from,char *msg,...) { char *tmp2; tmp2=malloc(strlen(msg)+4); snprintf(tmp2,strlen(msg)+3,"%s\r\n",msg); mywrite(fd,tmp2); free(tmp2); } void c_say(int fd,char *from,char *msg,...) { privmsg(fd,from,msg); } void c_nick(int fd,char *from,char *msg,...) { free(myuser->nick); myuser->nick=strdup(msg); irc_nick(fd,myuser->nick); } void message_handler(int fd,char *from,struct user *user,char *msg,int redones) { struct entry *m; union hack lol; char *command; char *args; // char *magic; char tmp[512]; int len; int sz; //debug_time(fd,from); if(user->nick) { if(strcmp(user->nick,myuser->nick)) { if(locked_down) return; for(sz=0;shitlist[sz];sz++) { if(!strcmp(shitlist[sz],user->nick)) { return; } } } } if(redirect_to_fd != -1) { fd=redirect_to_fd; } if(recording) { debug_time(fd,from,"writing to log..."); snprintf(tmp,sizeof(tmp)-1,"<%s> %s",user->nick,msg); append_file(fd,user->nick,LOG,tmp,'\n'); debug_time(fd,from,"finished writing to log."); } len=strchr(msg,'*')?strchr(msg,'*')-msg:strlen(myuser->nick); if(!strncmp(msg,myuser->nick,len)) { if(msg[len] == '*') len++; if(msg[len] == ',' || msg[len] == ':') { if(msg[len+1] == ' ') { msg+=len+1; msg[0]=trigger_char; } } } //if(*msg == trigger_char) *msg='!'; //if(*msg != '!') { // return; //} command=strdup(msg); if(command[0] == trigger_char) { command++; } else { return; } //privmsg(fd,from,command); if((args=strchr(command,' '))) { *args=0; args++; } //if(!strncmp(command,"lambda",6)) { // command+=8; // if((args=strchr(command,' '))) { // *args=0; // args++; // } // args=format_magic(fd,from,user,args,":/"); //} if((lol.data=ht_getvalue(&builtin,command))) { func=lol.func; // privmsg(fd,from,"found it in builtins HT."); func(fd,from,args,user); //if(args != (command + strlen(command) + 2)) { // free(args); //} } else if(redones < 5) { debug_time(fd,from,"checking aliases..."); command--;// :> if((m=ht_getnode(&alias,command)) != NULL) { sz=(strlen(msg)-strlen(m->original)+strlen(m->target)+1); redo=format_magic(fd,from,user,m->target,*(msg+strlen(m->original)+1)=='\n'?"":(msg+strlen(m->original)+1)); message_handler(fd,from,user,redo,redones+1); free(redo); redo=0; return; } debug_time(fd,from,"finished checking aliases. not found."); redo=0; if(debug) { snprintf(tmp,sizeof(tmp)-1,"command not found: '%s' with args '%s'",command,args); privmsg(fd,from,tmp); } } if(redones >5) { privmsg(fd,from,"I don't know if I'll ever get out of this alias hole you're telling me to dig. Fuck this."); } } void line_handler(int fd,char *line) {//this should be built into the libary? char *s=line,*t=0,*u=0; struct user *user=malloc(sizeof(struct user)); user->nick=0; user->user=0; user->host=0; if(strchr(line,'\r')) *strchr(line,'\r')=0; if(strchr(line,'\n')) *strchr(line,'\n')=0; printf("line: '%s'\n",line); //:nick!user@host MERP DERP :message //:nick!user@host s t :u //:armitage.hacking.allowed.org MERP DERP :message //:nickhost s t :u //only sub-parse nickuserhost stuff if starts with : //strchr doesn't like null pointers. :/ why not just take them and return null? //check that I haven't gone past the end of the string? nah. it should take care of itself. if(recording_raw) { append_file(fd,"epoch",RAWLOG,line,'\n'); } // rewrite this shit. if(line[0]==':') { if((user->nick=strchr(line,':'))) { *(user->nick)=0; (user->nick)++; } } if(user->nick) { if((s=strchr((user->nick),' '))) { *s=0; s++; if((t=strchr(s,' '))) { *t=0; t++; if((u=strchr(t,' '))) {//: *u=0; u++; } } } if(((user->user)=strchr((user->nick),'!'))) { *(user->user)=0; (user->user)++; if(((user->host)=strchr((user->user),'@'))) { *(user->host)=0; (user->host)++; } } else { user->host=user->nick; } } //all this shit. printf("<%s!%s@%s> '%s' '%s' '%s'\n", user->nick, user->user, user->host, s,t,u); if(!user->user && s) { //server message if(!strcmp(s,"433")) {//nick already used. srand(time(NULL)*getpid()); myuser->nick[strlen(myuser->nick)-3]=(rand()%10)+'0'; myuser->nick[strlen(myuser->nick)-2]=(rand()%10)+'0'; myuser->nick[strlen(myuser->nick)-1]=(rand()%10)+'0'; irc_nick(fd,myuser->nick); } if(!strcmp(s,"004")) {//we're connected. startup_stuff(fd); } } if(s && t && u) { if(!strcmp(s,"PRIVMSG") && strcmp(user->nick,myuser->nick)) { if(strcmp(user->nick,myuser->nick)) { message_handler(fd,*t=='#'?t:user->nick,user,++u,0); } else { if(debug) privmsg(fd,*t=='#'?t:user->nick,"This server has an echo"); } } } if(s && user->nick && t) { if(!strcmp(s,"JOIN")) { irc_mode(fd,t+1,"+o",user->nick);//why t+1? it starts with :? } if(!strcmp(s,"MODE") && mode_magic) { if(u) { if(*u == '-') {//auto-give modes back that are removed in front of segfault. *u='+'; irc_mode(fd,t,u,"");//u contains the nick the mode is being removed from. } } } //:Ishikawa-!~epoch@localhost NICK :checking if(!strcmp(s,"NICK")) { if(!strcmp(user->nick,myuser->nick)) { free(myuser->nick); myuser->nick=strdup(t+1); } } } free(user); } int main(int argc,char *argv[]) { int fd; struct passwd *pwd; struct rlimit nofile; char *s,*p; int c; inittable(&builtin,TSIZE); #define BUILDIN(a,b) ht_setkey(&builtin,a,(void *)((union hack){(void (*)(int,...))b}.data)) BUILDIN("builtin",c_builtin); BUILDIN("builtins",c_builtins); BUILDIN("raw",c_raw); BUILDIN("leetsetout",c_leetsetout); BUILDIN("resetout",c_resetout); BUILDIN("botup",c_botup); BUILDIN("linelimit",c_linelimit); BUILDIN("nick",c_nick); BUILDIN("tailunlock",c_tailunlock); BUILDIN("changetail",c_changetail); BUILDIN("tails",c_tails); BUILDIN("record",c_record); BUILDIN("rawrecord",c_rawrecord); BUILDIN("leettail",c_leettail); BUILDIN("leetuntail",c_leetuntail); BUILDIN("leetappend",c_leetappend); BUILDIN("untail",c_untail); BUILDIN("say",c_say); BUILDIN("id",c_id); BUILDIN("kill",c_kill); BUILDIN("alias",c_alias_h); BUILDIN("aliases",c_aliases_h); mode_magic=0; trigger_char='!'; redirect_to_fd=-1; debug=0; locked_down=(argc>2); lines_sent=0; line_limit=25; recording=0; recording_raw=0; start_time=time(0); redo=0; inittable(&alias,TSIZE); if(getrlimit(RLIMIT_NOFILE,&nofile) == -1) { printf("couldn't get max open files limit.\n"); exit(0); } else { maxtails=nofile.rlim_max; tailf=malloc(sizeof(struct tail) * (maxtails + 1)); } myuser=malloc(sizeof(struct user)); myuser->nick=strdup(argc>1?argv[1]:NICK); myuser->user="I_dunno"; myuser->host="I_dunno"; snprintf(pid,6,"%d",getpid()); printf("starting segfault...\n"); if(!getuid() || !geteuid()) { s=getenv("seguser"); pwd=getpwnam(s?s:MYUSER); if(!pwd) { printf("I'm running with euid or uid of 0 and I can't find myself."); return 0; } setgroups(0,0); setgid(pwd->pw_gid); setuid(pwd->pw_uid); } else { pwd=getpwuid(getuid()); printf("going to run segfault as user %s\n",pwd->pw_name); if(!pwd) { printf("well, shit. I don't know who I am."); return 0; } } for(c=0;cnick, // "segfault segfault segfault :segfault"); printf("cd %s\n",pwd->pw_dir); chdir(getenv("seghome")?getenv("seghome"):pwd->pw_dir); prestartup_stuff(fd); return runit(fd,line_handler,extra_handler); }