/* userrec.c -- handles: add_q() del_q() str2flags() flags2str() a bunch of functions to find and change user records dprintf'ized, 10nov95 */ #if HAVE_CONFIG_H #include #endif #include #include #include #include #include #include "eggdrop.h" #include "users.h" #include "proto.h" extern char botname[]; extern char botuser[]; extern int serv; extern char curchan[]; extern struct dcc_t dcc[]; extern int dcc_total; extern char userfile[]; extern int cx_line; extern char cx_file[]; extern int bitch; extern int require_p; extern int require_x; /* don't send out to sharebots */ int noshare=1; /* user records are stored here */ struct userrec *userlist=NULL; /* last accessed user record */ struct userrec *lastuser=NULL; struct userrec *banu=NULL,*ignu=NULL; /* hey let's allow the config file to specify the names for flags! */ /* gee wally i like that idea, that could cause LOTS of trouble! */ char flag1='1'; /* I used USER FLAG +1 as new +w flag. NAROD. */ char flag2='2'; char flag3='3'; char flag4='4'; char flag5='5'; char flag6='6'; char flag7='7'; char flag8='8'; char flag9='9'; char flag0='0'; /* temporary cache accounting */ int cache_hit=0,cache_miss=0; struct eggqueue *add_q(ss,q) char *ss; struct eggqueue *q; { char s[512]; struct eggqueue *x; char s1[121],*p; strcpy(s,ss); do { p=strchr(s,','); if (p!=NULL) { *p=0; p++; strcpy(s1,p); } else s1[0]=0; rmspace(s); rmspace(s1); x=(struct eggqueue *)nmalloc(sizeof(struct eggqueue)); x->next=q; x->item=(char *)nmalloc(strlen(s)+1); strcpy(x->item,s); s[0]=0; strcpy(s,s1); } while (s[0]); return x; } struct eggqueue *del_q(s,q,ok) char *s; struct eggqueue *q; int *ok; { struct eggqueue *x,*ret,*old; x=q; ret=q; old=q; *ok=0; while (x!=NULL) { if (strcasecmp(x->item,s)==0) { if (x==ret) { ret=(x->next); nfree(x->item); nfree(x); x=ret; } else { old->next=x->next; nfree(x->item); nfree(x); x=old->next; } *ok=1; } else { old=x; x=x->next; } } return ret; } /* memory we should be using */ int expmem_users() { int tot,i; struct userrec *u; struct eggqueue *s; tot=0; for (i=0; iuser; else u=NULL; } while (u!=NULL) { if (u->email!=NULL) tot+=strlen(u->email)+1; if (u->dccdir!=NULL) tot+=strlen(u->dccdir)+1; if (u->comment!=NULL) tot+=strlen(u->comment)+1; if (u->info!=NULL) tot+=strlen(u->info)+1; if (u->xtra!=NULL) tot+=strlen(u->xtra)+1; s=u->host; while (s!=NULL) { tot+=strlen(s->item)+1; tot+=sizeof(struct eggqueue); s=s->next; } tot+=sizeof(struct userrec); u=u->next; } } return tot; } unsigned int str2flags(s) char *s; { unsigned int i,f=0; for (i=0; inext; } return tot; } struct userrec *get_user_by_handle(bu,handle) struct userrec *bu; char *handle; { struct userrec *u=bu,*ret; if (handle==NULL) return NULL; rmspace(handle); if (!handle[0]) return NULL; if ((lastuser!=NULL) && (strcasecmp(lastuser->handle,handle)==0) && (bu==userlist)) { cache_hit++; return lastuser; } if ((banu!=NULL) && (strcmp(handle,BAN_NAME)==0) && (bu==userlist)) { cache_hit++; return banu; } if ((ignu!=NULL) && (strcmp(handle,IGNORE_NAME)==0) && (bu==userlist)) { cache_hit++; return ignu; } if (bu==userlist) { ret=check_chanlist_hand(handle); if (ret!=NULL) { cache_hit++; return ret; } cache_miss++; } while (u!=NULL) { if (strcasecmp(u->handle,handle)==0) { if ((strcmp(handle,BAN_NAME)==0) && (bu==userlist)) banu=u; else if ((strcmp(handle,IGNORE_NAME)==0) && (bu==userlist)) ignu=u; else if (bu==userlist) lastuser=u; return u; } u=u->next; } return NULL; } int is_user(handle) char *handle; { struct userrec *u; u=get_user_by_handle(userlist,handle); if (u==NULL) return 0; else return 1; } /* fix capitalization, etc */ void correct_handle(handle) char *handle; { struct userrec *u; u=get_user_by_handle(userlist,handle); if (u==NULL) return; strcpy(handle,u->handle); } void clear_userlist(bu) struct userrec *bu; { struct userrec *u=bu,*v; while (u!=NULL) { clearq(u->host); if (u->email!=NULL) nfree(u->email); if (u->dccdir!=NULL) nfree(u->dccdir); if (u->comment!=NULL) nfree(u->comment); if (u->info!=NULL) nfree(u->info); if (u->xtra!=NULL) nfree(u->xtra); v=u->next; nfree(u); u=v; } if (userlist==bu) { clear_chanlist(); lastuser=banu=ignu=NULL; } /* remember to set your userlist to NULL after calling this */ } /* find CLOSEST host match */ /* (if "*!*@*" and "*!*@*clemson.edu" both match, use the latter!) */ /* 26feb: CHECK THE CHANLIST FIRST to possibly avoid needless search */ struct userrec *get_user_by_host(host) char *host; { struct userrec *u=userlist,*ret; struct eggqueue *q; int cnt,i; if (host==NULL) return NULL; rmspace(host); if (!host[0]) return NULL; ret=check_chanlist(host); cnt=0; if (ret!=NULL) { cache_hit++; return ret; } cache_miss++; while (u!=NULL) { q=u->host; while (q!=NULL) { i=wild_match(q->item,host); if (i>cnt) { ret=u; cnt=i; } q=q->next; } u=u->next; } if (ret!=NULL) { lastuser=ret; set_chanlist(host,ret); } return ret; } void get_handle_by_host(nick,host) char *nick,*host; { struct userrec *u; u=get_user_by_host(host); if (u==NULL) { nick[0]='*'; nick[1]=0; return; } strcpy(nick,u->handle); } struct userrec *get_user_by_equal_host(host) char *host; { struct userrec *u=userlist; struct eggqueue *q; while (u!=NULL) { q=u->host; while (q!=NULL) { if (strcasecmp(q->item,host)==0) return u; q=q->next; } u=u->next; } return NULL; } /* try: pass_match_by_host("nopass",host) will return 1 if no password is set for that host */ int pass_match_by_host(pass,host) char *pass,*host; { struct userrec *u; u=get_user_by_host(host); if (u==NULL) return 0; if (!bitch && (strcasecmp(u->pass,"nopass")==0)) return 1; if (strcasecmp(u->pass,pass)!=0) return 0; else return 1; } int pass_match_by_handle(pass,handle) char *pass,*handle; { struct userrec *u; u=get_user_by_handle(userlist,handle); if (u==NULL) return 0; if (!bitch && (strcasecmp(u->pass,"nopass")==0)) return 1; if (strcasecmp(u->pass,pass)!=0) return 0; else return 1; } void get_pass_by_handle(handle,pass) char *handle,*pass; { struct userrec *u; u=get_user_by_handle(userlist,handle); if (u==NULL) { pass[0]=0; return; } strcpy(pass,u->pass); return; } int write_user(u,f) struct userrec *u; FILE *f; { char s[181]; struct eggqueue *q; /* if (u->flags&USER_PURGE) return; */ flags2str((u->flags & USER_MASK),s); /* for user-created flags that could have any name, depending: */ if ((u->flags & USER_FELLOW) || (u->flags & USER_FLAG1)) strcat(s,"w"); if ((u->flags & USER_UNBAN) || (u->flags & USER_FLAG2)) strcat(s,"u"); if (u->flags & USER_FLAG3) strcat(s,"3"); if (u->flags & USER_FLAG4) strcat(s,"4"); if (u->flags & USER_FLAG5) strcat(s,"5"); if (u->flags & USER_FLAG6) strcat(s,"6"); if (u->flags & USER_FLAG7) strcat(s,"7"); if (u->flags & USER_FLAG8) strcat(s,"8"); if (u->flags & USER_FLAG9) strcat(s,"9"); if (u->flags & USER_FLAG0) strcat(s,"0"); if (fprintf(f,"%-10snone %-10s%-25s%lu\n",u->handle,u->pass,s,u->laston) ==EOF) return 0; q=u->host; s[0]=0; while (q!=NULL) { if (!s[0]) { strcpy(s,"- "); strcat(s,q->item); } else { if (strlen(s)+strlen(q->item)+2>70) { if (fprintf(f,"%s\n",s) == EOF) return 0; strcpy(s,"- "); strcat(s,q->item); } else { strcat(s,", "); strcat(s,q->item); } } q=q->next; } if (s[0]) { if (fprintf(f,"%s\n",s)==EOF) return 0; } if (u->email!=NULL) { if (fprintf(f,"+ %s\n",u->email)==EOF) return 0; } if (u->dccdir!=NULL) { if (fprintf(f,"* %s\n",u->dccdir)==EOF) return 0; } if (u->comment!=NULL) { if (fprintf(f,"= %s\n",u->comment)==EOF) return 0; } if (u->info!=NULL) { if (fprintf(f,": %s\n",u->info)==EOF) return 0; } if (u->xtra!=NULL) { char *p=u->xtra; while (strlen(p)>160) { char *q=p+160,c; while ((*q!=' ') && (q!=p)) q--; if (q==p) q=p+160; c=*q; *q=0; if (fprintf(f,". %s\n",p)==EOF) { *q=c; return 0; } *q=c; if (c==' ') p=q+1; else p=q; } if (fprintf(f,". %s\n",p)==EOF) return 0; } return 1; } /* rewrite the entire user file */ void write_userfile() { FILE *f; char s[121],s1[81]; time_t tt; struct userrec *u; int ok; context; if (userlist==NULL) return; /* no point in saving userfile */ sprintf(s,"%s~new",userfile); f=fopen(s,"w"); if (f==NULL) { log(LOG_MISC,"ERROR in writing user file."); return; } log(LOG_MISC,"Writing user file ..."); tt=time(NULL); strcpy(s1,ctime(&tt)); fprintf(f,"# wrote user file: %s",s1); context; ok=1; u=userlist; while ((u!=NULL) && (ok)) { ok=write_user(u,f); u=u->next; } context; if (!ok) { log(LOG_MISC,"ERROR in writing user file."); return; } fclose(f); unlink(userfile); sprintf(s,"%s~new",userfile); #ifdef RENAME rename(s,userfile); #else movefile(s,userfile); #endif chmod(userfile,0600); /* make it -rw------- */ context; } /* note: save-user no longer exists */ /* note: purge-user no longer exists */ void change_pass_by_handle(handle,pass) char *handle,*pass; { struct userrec *u; u=get_user_by_handle(userlist,handle); if (u==NULL) return; strcpy(u->pass,pass); if ((!noshare) && (!(u->flags&USER_BOT))) shareout("chpass %s %s\n",handle,pass); } void change_pass_by_host(host,pass) char *host,*pass; { struct userrec *u; u=get_user_by_host(host); if (u==NULL) return; strcpy(u->pass,pass); if ((!noshare) && (!(u->flags&USER_BOT))) shareout("chpass %s %s\n",u->handle,pass); } int change_handle(oldh,newh) char *oldh,*newh; { struct userrec *u; u=get_user_by_handle(userlist,oldh); if (u==NULL) return 0; /* nothing that will confuse the userfile */ if ((newh[1]==0) && ((newh[0]=='+') || (newh[0]=='*') || (newh[0]==':') || (newh[0]=='=') || (newh[0]=='.') || (newh[0]=='-'))) return 0; strcpy(u->handle,newh); if ((!noshare) && (!(u->flags&USER_BOT))) shareout("chhand %s %s\n",oldh,newh); return 1; } struct userrec *adduser(bu,handle,host,pass,flags) struct userrec *bu; char *handle,*host,*pass; int flags; { struct userrec *u; u=(struct userrec *)nmalloc(sizeof(struct userrec)); u->next=bu; bu=u; strcpy(u->handle,handle); strcpy(u->pass,pass); u->host=NULL; /* strip out commas -- they're illegal */ if (host[0]) { char *p=strchr(host,','); while (p!=NULL) { *p='?'; p=strchr(host,','); } u->host=add_q(host,u->host); } else { u->host=add_q("none",u->host); } u->flags=flags; u->laston=0L; u->email=u->dccdir=u->comment=u->info=u->xtra=NULL; if ((!noshare) && (handle[0]!='*') && (!(flags&USER_BOT))) shareout("newuser %s %s %s %d\n",handle,host,pass,flags); if (bu==userlist) clear_chanlist(); return bu; } /* create a copy of the entire userlist (for sending user lists to clone bots) -- userlist is reversed in the process, which is OK because the receiving bot reverses the list AGAIN when saving */ /* t=1: copy only tandem-bots -- t=0: copy everything BUT tandem-bots */ struct userrec *dup_userlist(t) int t; { struct userrec *u,*u1,*nu; struct eggqueue *q; nu=NULL; u=userlist; while (u!=NULL) { if (((u->flags&USER_BOT) && (t)) || (!(u->flags&USER_BOT) && (!t))) { u1=(struct userrec *)nmalloc(sizeof(struct userrec)); u1->next=nu; nu=u1; strcpy(nu->handle,u->handle); strcpy(nu->pass,u->pass); q=u->host; nu->host=NULL; while (q!=NULL) { nu->host=add_q(q->item,nu->host); q=q->next; } nu->flags=u->flags; nu->laston=u->laston; if (u->email!=NULL) { nu->email=(char *)nmalloc(strlen(u->email)+1); strcpy(nu->email,u->email); } else nu->email=NULL; if (u->dccdir!=NULL) { nu->dccdir=(char *)nmalloc(strlen(u->dccdir)+1); strcpy(nu->dccdir,u->dccdir); } else nu->dccdir=NULL; if (u->comment!=NULL) { nu->comment=(char *)nmalloc(strlen(u->comment)+1); strcpy(nu->comment,u->comment); } else nu->comment=NULL; if (u->info!=NULL) { nu->info=(char *)nmalloc(strlen(u->info)+1); strcpy(nu->info,u->info); } else nu->info=NULL; if (u->xtra!=NULL) { nu->xtra=(char *)nmalloc(strlen(u->xtra)+1); strcpy(nu->xtra,u->xtra); } else nu->xtra=NULL; } u=u->next; } return nu; } void freeuser(u) struct userrec *u; { clearq(u->host); if (u->email!=NULL) nfree(u->email); if (u->dccdir!=NULL) nfree(u->dccdir); if (u->comment!=NULL) nfree(u->comment); if (u->info!=NULL) nfree(u->info); if (u->xtra!=NULL) nfree(u->xtra); nfree(u); } int deluser(handle) char *handle; { struct userrec *u=userlist,*prev=NULL; int fnd=0; while ((u!=NULL) && (!fnd)) { if (strcasecmp(u->handle,handle)==0) fnd=1; else { prev=u; u=u->next; } } if (!fnd) return 0; if (prev==NULL) userlist=u->next; else prev->next=u->next; if ((!noshare) && (handle[0]!='*') && (!(u->flags&USER_BOT))) shareout("killuser %s\n",handle); freeuser(u); clear_chanlist(); lastuser=NULL; if (strcmp(handle,BAN_NAME)==0) banu=NULL; if (strcmp(handle,IGNORE_NAME)==0) ignu=NULL; return 1; } int delhost_by_handle(handle,host) char *handle,*host; { struct userrec *u; int i; u=get_user_by_handle(userlist,handle); if (u==NULL) return 0; u->host=del_q(host,u->host,&i); if (u->host==NULL) u->host=add_q("none",u->host); if ((!noshare) && (i) && (!(u->flags&USER_BOT))) shareout("-host %s %s\n",handle,host); clear_chanlist(); return i; } int ishost_for_handle(handle,host) char *handle,*host; { struct userrec *u; struct eggqueue *q; u=get_user_by_handle(userlist,handle); if (u==NULL) return 0; if (u->host==NULL) return 0; q=u->host; while (q!=NULL) { if (strcasecmp(q->item,host)==0) return 1; q=q->next; } return 0; } void addhost_by_handle2(bu,handle,hst) struct userrec *bu; char *handle,*hst; { struct userrec *u; int i; char *p; struct eggqueue *q; char host[161]; u=get_user_by_handle(bu,handle); strcpy(host,hst); if (u==NULL) return; if (u->host!=NULL) if (strcmp(u->host->item,"none")==0) u->host=del_q("none",u->host,&i); p=strchr(host,','); /* commas are forbidden */ while (p!=NULL) { *p='?'; p=strchr(host,','); } /* fred1: check for redundant hostmasks with */ /* controversial "superpenis" algorithm ;) */ q=u->host; while (q!=NULL) { if (wild_match(host,q->item)) q=u->host=del_q(q->item,u->host,&i); else q=q->next; } u->host=add_q(host,u->host); } void addhost_by_handle(handle,host) char *handle,*host; { struct userrec *u; addhost_by_handle2(userlist,handle,host); /* u will be cached, so really no overhead, even tho this looks dumb: */ u=get_user_by_handle(userlist,handle); if ((!noshare) && (!(u->flags&USER_BOT))) shareout("+host %s %s\n",handle,host); clear_chanlist(); } void get_handle_email(handle,s) char *handle; char *s; { struct userrec *u; u=get_user_by_handle(userlist,handle); if (u==NULL) { s[0]=0; return; } if (u->email==NULL) { s[0]=0; return; } strcpy(s,u->email); return; } void get_handle_dccdir(handle,s) char *handle; char *s; { struct userrec *u; u=get_user_by_handle(userlist,handle); if (u==NULL) { s[0]=0; return; } if (u->dccdir==NULL) { s[0]=0; return; } strcpy(s,u->dccdir); return; } void get_handle_comment(handle,s) char *handle; char *s; { struct userrec *u; u=get_user_by_handle(userlist,handle); if (u==NULL) { s[0]=0; return; } if (u->comment==NULL) { s[0]=0; return; } strcpy(s,u->comment); return; } void get_handle_info(handle,s) char *handle; char *s; { struct userrec *u; u=get_user_by_handle(userlist,handle); if (u==NULL) { s[0]=0; return; } if (u->info==NULL) { s[0]=0; return; } strcpy(s,u->info); return; } void get_handle_xtra(handle,s) char *handle; char *s; { struct userrec *u; u=get_user_by_handle(userlist,handle); if (u==NULL) { s[0]=0; return; } if (u->xtra==NULL) { s[0]=0; return; } strcpy(s,u->xtra); return; } /* max length for these things is now 160 */ void set_handle_email(bu,handle,email) struct userrec *bu; char *handle,*email; { struct userrec *u; if (strlen(email)>160) email[160]=0; u=get_user_by_handle(bu,handle); if (u==NULL) return; if (u->email!=NULL) nfree(u->email); if (email[0]) { u->email=(char *)nmalloc(strlen(email)+1); strcpy(u->email,email); } else u->email=NULL; if ((!noshare) && (!(u->flags&USER_BOT))) shareout("chemail %s %s\n",handle,email); } void set_handle_dccdir(bu,handle,dir) struct userrec *bu; char *handle,*dir; { struct userrec *u; if (strlen(dir)>160) dir[160]=0; u=get_user_by_handle(bu,handle); if (u==NULL) return; if (u->dccdir!=NULL) nfree(u->dccdir); if (dir[0]) { u->dccdir=(char *)nmalloc(strlen(dir)+1); strcpy(u->dccdir,dir); } else u->dccdir=NULL; if ((!noshare) && (!(u->flags&USER_BOT))) shareout("chdccdir %s %s\n",handle,dir); } void set_handle_comment(bu,handle,comment) struct userrec *bu; char *handle,*comment; { struct userrec *u; if (strlen(comment)>160) comment[160]=0; u=get_user_by_handle(bu,handle); if (u==NULL) return; if (u->comment!=NULL) nfree(u->comment); if (comment[0]) { u->comment=(char *)nmalloc(strlen(comment)+1); strcpy(u->comment,comment); } else u->comment=NULL; if ((!noshare) && (!(u->flags&USER_BOT))) shareout("chcomment %s %s\n",handle,comment); } void set_handle_info(bu,handle,info) struct userrec *bu; char *handle,*info; { struct userrec *u; char *p; if (strlen(info)>80) info[80]=0; for (p=info; *p; ) { if ((*p < 32) || (*p > 126)) strcpy(p,p+1); else p++; } u=get_user_by_handle(bu,handle); if (u==NULL) return; if (u->info!=NULL) nfree(u->info); if (info[0]) { u->info=(char *)nmalloc(strlen(info)+1); strcpy(u->info,info); } else u->info=NULL; if ((!noshare) && (!(u->flags&USER_BOT))) shareout("chinfo %s %s\n",handle,info); } void set_handle_xtra(bu,handle,xtra) struct userrec *bu; char *handle,*xtra; { struct userrec *u; if (strlen(xtra)>500) xtra[500]=0; u=get_user_by_handle(bu,handle); if (u==NULL) return; if (u->xtra!=NULL) nfree(u->xtra); if (xtra[0]) { u->xtra=(char *)nmalloc(strlen(xtra)+1); strcpy(u->xtra,xtra); } else u->xtra=NULL; if ((!noshare) && (!(u->flags&USER_BOT))) shareout("chxtra %s %s\n",handle,xtra); } int chg_attr_u(u,chg,which) struct userrec *u; char chg; int which; { if (u==NULL) return 0; if (chg=='+') { if (u->flags&which) return 0; u->flags |= which; if ((!noshare) && (!(u->flags&USER_BOT))) shareout("+attr %s %d\n",u->handle,which); return 1; } else { if (!(u->flags&which)) return 0; u->flags &= ~which; if ((!noshare) && (!(u->flags&USER_BOT))) shareout("-attr %s %d\n",u->handle,which); return 1; } } int chg_attr_by_handle(handle,chg,which) char *handle,chg; int which; { struct userrec *u; u=get_user_by_handle(userlist,handle); if (u!=NULL) return chg_attr_u(u,chg,which); else return 0; } int chg_attr_by_host(host,chg,which) char *host,chg; int which; { struct userrec *u; u=get_user_by_host(host); if (u!=NULL) return chg_attr_u(u,chg,which); else return 0; } /* return 1 if it was successful */ /* change attr by handle or host (depending on whether ident has '@') */ int change_attr(ident,chg,which) char *ident,chg; int which; { if (ident==NULL) return 0; if (!ident[0]) return 0; if (strchr(ident,'@')==NULL) { /* handle? */ return chg_attr_by_handle(ident,chg,which); } else return chg_attr_by_host(ident,chg,which); } int get_attr_handle(handle) char *handle; { struct userrec *u; u=get_user_by_handle(userlist,handle); if (u==NULL) return 0; return u->flags; } void set_attr_handle(handle,flags) char *handle; unsigned int flags; { struct userrec *u; u=get_user_by_handle(userlist,handle); if (u==NULL) return; u->flags=flags; if ((!noshare) && (!(u->flags&USER_BOT))) shareout("chattr %s %d\n",u->handle,flags); } int get_attr_host(host) char *host; { struct userrec *u; u=get_user_by_host(host); if (u==NULL) return 0; return u->flags; } int flags_ok(req,have) int req,have; { if (have&USER_OWNER) return 1; if ((have&USER_MASTER) && !(req&USER_OWNER)) return 1; if (((have&USER_FELLOW) || (have&USER_FLAG1)) && !(req&USER_MASTER) && !(req&USER_OWNER)) return 1; if ((!require_x) && (have&USER_OP)) have|=USER_XFER; if ((!require_p) && (have&USER_OP)) have|=USER_PARTY; return ((have&req) == req); }