]>
Commit | Line | Data |
---|---|---|
1 | #include "authext.h" | |
2 | #include "../core/nsmalloc.h" | |
3 | #include "../core/error.h" | |
4 | #include "../lib/sstring.h" | |
5 | #include "../lib/irc_string.h" | |
6 | #include "../nick/nick.h" | |
7 | #include "../core/hooks.h" | |
8 | #include "../lib/strlfunc.h" | |
9 | #include "../lib/version.h" | |
10 | ||
11 | #include <string.h> | |
12 | #include <stdio.h> | |
13 | ||
14 | MODULE_VERSION("") | |
15 | ||
16 | #define ALLOCUNIT 100 | |
17 | ||
18 | #define authnamehash(x) ((x)%AUTHNAMEHASHSIZE) | |
19 | #define authnamehashbyname(x) (crc32i(x)%AUTHNAMEHASHSIZE) | |
20 | ||
21 | authname *freeauthnames; | |
22 | authname *authnametable[AUTHNAMEHASHSIZE]; | |
23 | ||
24 | /* internal access only */ | |
25 | static authname *authnametablebyname[AUTHNAMEHASHSIZE]; | |
26 | ||
27 | static struct { | |
28 | sstring *name; | |
29 | int persistent; | |
30 | } authnameexts[MAXAUTHNAMEEXTS]; | |
31 | ||
32 | static void authextstats(int hooknum, void *arg); | |
33 | ||
34 | void _init(void) { | |
35 | freeauthnames=NULL; | |
36 | memset(authnametable,0,sizeof(authnametable)); | |
37 | memset(authnametablebyname,0,sizeof(authnametablebyname)); | |
38 | registerhook(HOOK_CORE_STATSREQUEST, &authextstats); | |
39 | } | |
40 | ||
41 | void _fini(void) { | |
42 | deregisterhook(HOOK_CORE_STATSREQUEST, &authextstats); | |
43 | nsfreeall(POOL_AUTHEXT); | |
44 | } | |
45 | ||
46 | authname *newauthname(void) { | |
47 | authname *anp; | |
48 | int i; | |
49 | ||
50 | if (freeauthnames==NULL) { | |
51 | freeauthnames=(authname *)nsmalloc(POOL_AUTHEXT, ALLOCUNIT*sizeof(authname)); | |
52 | for (i=0;i<(ALLOCUNIT-1);i++) { | |
53 | freeauthnames[i].next=&(freeauthnames[i+1]); | |
54 | } | |
55 | freeauthnames[ALLOCUNIT-1].next=NULL; | |
56 | } | |
57 | ||
58 | anp=freeauthnames; | |
59 | freeauthnames=anp->next; | |
60 | ||
61 | return anp; | |
62 | } | |
63 | ||
64 | void freeauthname (authname *anp) { | |
65 | anp->next=freeauthnames; | |
66 | freeauthnames=anp; | |
67 | } | |
68 | ||
69 | int registerauthnameext(const char *name, int persistent) { | |
70 | int i; | |
71 | ||
72 | if (findauthnameext(name)!=-1) { | |
73 | Error("nick",ERR_WARNING,"Tried to register duplicate authname extension %s",name); | |
74 | return -1; | |
75 | } | |
76 | ||
77 | for (i=0;i<MAXAUTHNAMEEXTS;i++) { | |
78 | if (authnameexts[i].name==NULL) { | |
79 | authnameexts[i].name=getsstring(name,100); | |
80 | authnameexts[i].persistent=persistent; | |
81 | return i; | |
82 | } | |
83 | } | |
84 | ||
85 | Error("nick",ERR_WARNING,"Tried to register too many authname extensions: %s",name); | |
86 | return -1; | |
87 | } | |
88 | ||
89 | int findauthnameext(const char *name) { | |
90 | int i; | |
91 | ||
92 | for (i=0;i<MAXAUTHNAMEEXTS;i++) { | |
93 | if (authnameexts[i].name!=NULL && !ircd_strcmp(name,authnameexts[i].name->content)) { | |
94 | return i; | |
95 | } | |
96 | } | |
97 | ||
98 | return -1; | |
99 | } | |
100 | ||
101 | void releaseauthnameext(int index) { | |
102 | int i; | |
103 | authname *anp; | |
104 | ||
105 | freesstring(authnameexts[index].name); | |
106 | authnameexts[index].name=NULL; | |
107 | ||
108 | for (i=0;i<AUTHNAMEHASHSIZE;i++) { | |
109 | for (anp=authnametable[i];anp;anp=anp->next) { | |
110 | anp->exts[index]=NULL; | |
111 | } | |
112 | } | |
113 | ||
114 | /* the contents of authnametablebyname should be identical */ | |
115 | } | |
116 | ||
117 | authname *findauthname(unsigned long userid) { | |
118 | authname *anp; | |
119 | ||
120 | if(!userid) | |
121 | return NULL; | |
122 | ||
123 | for (anp=authnametable[authnamehash(userid)];anp;anp=(authname *)anp->next) | |
124 | if (userid==anp->userid) | |
125 | return anp; | |
126 | ||
127 | return NULL; | |
128 | } | |
129 | ||
130 | authname *findauthnamebyname(const char *name) { | |
131 | authname *anp; | |
132 | ||
133 | if(!name) | |
134 | return NULL; | |
135 | ||
136 | for (anp=authnametablebyname[authnamehashbyname(name)];anp;anp=(authname *)anp->nextbyname) | |
137 | if (!ircd_strcmp(anp->name, name)) | |
138 | return anp; | |
139 | ||
140 | return NULL; | |
141 | } | |
142 | ||
143 | authname *findorcreateauthname(unsigned long userid, const char *name) { | |
144 | authname *anp; | |
145 | unsigned int thehash=authnamehash(userid), secondhash = authnamehashbyname(name); | |
146 | ||
147 | if(!userid || !name) | |
148 | return NULL; | |
149 | ||
150 | for (anp=authnametable[thehash];anp;anp=(authname *)anp->next) | |
151 | if (userid==anp->userid) | |
152 | return anp; | |
153 | ||
154 | anp=newauthname(); | |
155 | anp->userid=userid; | |
156 | strlcpy(anp->name, name, sizeof(anp->name)); | |
157 | anp->usercount=0; | |
158 | anp->marker=0; | |
159 | anp->flags=0; | |
160 | anp->nicks=NULL; | |
161 | memset(anp->exts, 0, MAXAUTHNAMEEXTS * sizeof(void *)); | |
162 | anp->next=(struct authname *)authnametable[thehash]; | |
163 | authnametable[thehash]=anp; | |
164 | ||
165 | anp->namebucket=secondhash; | |
166 | anp->nextbyname=(struct authname *)authnametablebyname[secondhash]; | |
167 | authnametablebyname[secondhash]=anp; | |
168 | ||
169 | return anp; | |
170 | } | |
171 | ||
172 | void releaseauthname(authname *anp) { | |
173 | authname **manp; | |
174 | int i, found; | |
175 | if (anp->usercount==0) { | |
176 | anp->nicks = NULL; | |
177 | ||
178 | for(i=0;i<MAXAUTHNAMEEXTS;i++) | |
179 | if(authnameexts[i].persistent && anp->exts[i]!=NULL) | |
180 | return; | |
181 | ||
182 | triggerhook(HOOK_AUTH_LOSTAUTHNAME, (void *)anp); | |
183 | found = 0; | |
184 | for(manp=&(authnametable[authnamehash(anp->userid)]);*manp;manp=(authname **)&((*manp)->next)) { | |
185 | if ((*manp)==anp) { | |
186 | (*manp)=(authname *)anp->next; | |
187 | found = 1; | |
188 | break; | |
189 | } | |
190 | } | |
191 | if(!found) { | |
192 | Error("nick",ERR_ERROR,"Unable to remove authname %lu from hashtable",anp->userid); | |
193 | return; | |
194 | } | |
195 | ||
196 | for(manp=&(authnametablebyname[anp->namebucket]);*manp;manp=(authname **)&((*manp)->nextbyname)) { | |
197 | if ((*manp)==anp) { | |
198 | (*manp)=(authname *)anp->nextbyname; | |
199 | freeauthname(anp); | |
200 | return; | |
201 | } | |
202 | } | |
203 | ||
204 | Error("nick",ERR_STOP,"Unable to remove authname %lu from byname hashtable, TABLES ARE INCONSISTENT -- DYING",anp->userid); | |
205 | } | |
206 | } | |
207 | ||
208 | unsigned int nextauthnamemarker(void) { | |
209 | int i; | |
210 | authname *anp; | |
211 | static unsigned int authnamemarker=0; | |
212 | ||
213 | authnamemarker++; | |
214 | if (!authnamemarker) { | |
215 | /* If we wrapped to zero, zap the marker on all records */ | |
216 | for (i=0;i<AUTHNAMEHASHSIZE;i++) | |
217 | for (anp=authnametable[i];anp;anp=anp->next) | |
218 | anp->marker=0; | |
219 | authnamemarker++; | |
220 | } | |
221 | ||
222 | return authnamemarker; | |
223 | } | |
224 | ||
225 | authname *getauthbyname(const char *name) { | |
226 | authname *a = findauthnamebyname(name); | |
227 | if(!a || !a->nicks) | |
228 | return NULL; | |
229 | ||
230 | return a; | |
231 | } | |
232 | ||
233 | static char *genstats(authname **hashtable, authname *(nextfn)(authname *)) { | |
234 | int i,curchain,maxchain=0,total=0,buckets=0; | |
235 | authname *ap; | |
236 | static char buf[100]; | |
237 | ||
238 | for (i=0;i<AUTHNAMEHASHSIZE;i++) { | |
239 | if (hashtable[i]!=NULL) { | |
240 | buckets++; | |
241 | curchain=0; | |
242 | for (ap=hashtable[i];ap;ap=nextfn(ap)) { | |
243 | total++; | |
244 | curchain++; | |
245 | } | |
246 | if (curchain>maxchain) { | |
247 | maxchain=curchain; | |
248 | } | |
249 | } | |
250 | } | |
251 | ||
252 | snprintf(buf, sizeof(buf), "%6d authexts (HASH: %6d/%6d, chain %3d)",total,buckets,AUTHNAMEHASHSIZE,maxchain); | |
253 | return buf; | |
254 | } | |
255 | ||
256 | static authname *nextbynext(authname *in) { | |
257 | return in->next; | |
258 | } | |
259 | ||
260 | static authname *nextbyname(authname *in) { | |
261 | return in->nextbyname; | |
262 | } | |
263 | ||
264 | static void authextstats(int hooknum, void *arg) { | |
265 | long level=(long)arg; | |
266 | char buf[100]; | |
267 | ||
268 | if (level>5) { | |
269 | /* Full stats */ | |
270 | snprintf(buf,sizeof(buf),"Authext : by id: %s", genstats(authnametable, nextbynext)); | |
271 | triggerhook(HOOK_CORE_STATSREPLY,buf); | |
272 | ||
273 | snprintf(buf,sizeof(buf),"Authext : by name: %s", genstats(authnametablebyname, nextbyname)); | |
274 | triggerhook(HOOK_CORE_STATSREPLY,buf); | |
275 | } | |
276 | } | |
277 |