]> jfr.im git - irc/quakenet/newserv.git/blob - whowas/whowas.c
GLINES: fix null pointer deref in trustgline / trustungline
[irc/quakenet/newserv.git] / whowas / whowas.c
1 #include <string.h>
2 #include <stdio.h>
3 #include "../core/hooks.h"
4 #include "../control/control.h"
5 #include "../irc/irc.h"
6 #include "../lib/irc_string.h"
7 #include "../lib/version.h"
8 #include "../core/config.h"
9 #include "whowas.h"
10
11 #define XStringify(x) Stringify(x)
12 #define Stringify(x) #x
13
14 MODULE_VERSION("");
15
16 whowas *whowasrecs;
17 int whowasoffset = 0;
18 int whowasmax;
19
20 whowas *whowas_fromnick(nick *np, int standalone) {
21 whowas *ww;
22 nick *wnp;
23 struct irc_in_addr ipaddress_canonical;
24 void *args[2];
25
26 /* Create a new record. */
27 if (standalone)
28 ww = malloc(sizeof(whowas));
29 else {
30 ww = &whowasrecs[whowasoffset];
31 whowas_clean(ww);
32 whowasoffset = (whowasoffset + 1) % whowasmax;
33 }
34
35 memset(ww, 0, sizeof(whowas));
36
37 wnp = &ww->nick;
38 memset(wnp, 0, sizeof(nick));
39 strncpy(wnp->nick, np->nick, NICKLEN + 1);
40 wnp->numeric = np->numeric;
41 strncpy(wnp->ident, np->ident, USERLEN + 1);
42
43 wnp->host = newhost();
44 memset(wnp->host, 0, sizeof(host));
45 wnp->host->name = getsstring(np->host->name->content, HOSTLEN);
46
47 wnp->realname = newrealname();
48 memset(wnp->realname, 0, sizeof(realname));
49 wnp->realname->name = getsstring(np->realname->name->content, REALLEN);
50 wnp->shident = np->shident ? getsstring(np->shident->content, 512) : NULL;
51 wnp->sethost = np->sethost ? getsstring(np->sethost->content, 512) : NULL;
52 wnp->opername = np->opername ? getsstring(np->opername->content, 512) : NULL;
53 wnp->umodes = np->umodes;
54 if (np->auth) {
55 wnp->auth = newauthname();
56 memset(wnp->auth, 0, sizeof(authname));
57 wnp->auth->userid = np->auth->userid;
58 strncpy(wnp->auth->name, np->auth->name, ACCOUNTLEN + 1);
59 wnp->authname = wnp->auth->name;
60 }
61 wnp->timestamp = np->timestamp;
62 wnp->accountts = np->accountts;
63 wnp->away = np->away ? getsstring(np->away->content, 512) : NULL;
64
65 memcpy(&wnp->ipaddress, &np->ipaddress, sizeof(struct irc_in_addr));
66
67 ip_canonicalize_tunnel(&ipaddress_canonical, &np->ipaddress);
68 wnp->ipnode = refnode(iptree, &ipaddress_canonical, PATRICIA_MAXBITS);
69
70 wnp->next = (nick *)ww; /* Yuck. */
71
72 ww->timestamp = getnettime();
73 ww->type = WHOWAS_USED;
74
75 args[0] = ww;
76 args[1] = np;
77 triggerhook(HOOK_WHOWAS_NEWRECORD, args);
78
79 return ww;
80 }
81
82 void whowas_clean(whowas *ww) {
83 nick *np;
84
85 if (!ww || ww->type == WHOWAS_UNUSED)
86 return;
87
88 triggerhook(HOOK_WHOWAS_LOSTRECORD, ww);
89
90 np = &ww->nick;
91 freesstring(np->host->name);
92 freehost(np->host);
93 freesstring(np->realname->name);
94 freerealname(np->realname);
95 freesstring(np->shident);
96 freesstring(np->sethost);
97 freesstring(np->opername);
98 freeauthname(np->auth);
99 freesstring(np->away);
100 derefnode(iptree, np->ipnode);
101 freesstring(ww->reason);
102 freesstring(ww->newnick);
103 ww->type = WHOWAS_UNUSED;
104 }
105
106 void whowas_free(whowas *ww) {
107 whowas_clean(ww);
108 free(ww);
109 }
110
111 static void whowas_handlequitorkill(int hooknum, void *arg) {
112 void **args = arg;
113 nick *np = args[0];
114 char *reason = args[1];
115 char *rreason;
116 char resbuf[512];
117 whowas *ww;
118
119 /* Create a new record. */
120 ww = whowas_fromnick(np, 0);
121
122 if (hooknum == HOOK_NICK_KILL) {
123 if ((rreason = strchr(reason, ' '))) {
124 sprintf(resbuf, "Killed%s", rreason);
125 reason = resbuf;
126 }
127
128 ww->type = WHOWAS_KILL;
129 } else {
130 if (strncmp(reason, "G-lined", 7) == 0)
131 ww->type = WHOWAS_KILL;
132 else
133 ww->type = WHOWAS_QUIT;
134 }
135
136 ww->reason = getsstring(reason, WW_REASONLEN);
137 }
138
139 static void whowas_handlerename(int hooknum, void *arg) {
140 void **args = arg;
141 nick *np = args[0];
142 char *oldnick = args[1];
143 whowas *ww;
144 nick *wnp;
145
146 ww = whowas_fromnick(np, 0);
147 ww->type = WHOWAS_RENAME;
148 wnp = &ww->nick;
149 ww->newnick = getsstring(wnp->nick, NICKLEN);
150 strncpy(wnp->nick, oldnick, NICKLEN + 1);
151 }
152
153 whowas *whowas_chase(const char *target, int maxage) {
154 whowas *ww;
155 nick *wnp;
156 time_t now;
157 int i;
158
159 now = getnettime();
160
161 for (i = whowasoffset + whowasmax - 1; i >= whowasoffset; i--) {
162 ww = &whowasrecs[i % whowasmax];
163
164 if (ww->type == WHOWAS_UNUSED)
165 continue;
166
167 wnp = &ww->nick;
168
169 if (ww->timestamp < now - maxage)
170 break; /* records are in timestamp order, we're done */
171
172 if (ircd_strcmp(wnp->nick, target) == 0)
173 return ww;
174 }
175
176 return NULL;
177 }
178
179 const char *whowas_format(whowas *ww) {
180 nick *np = &ww->nick;
181 static char buf[512];
182 char timebuf[30];
183 char hostmask[512];
184
185 snprintf(hostmask, sizeof(hostmask), "%s!%s@%s%s%s [%s] (%s)",
186 np->nick, np->ident, np->host->name->content,
187 np->auth ? "/" : "", np->auth ? np->authname : "",
188 IPtostr(np->ipaddress),
189 printflags(np->umodes, umodeflags));
190 strftime(timebuf, sizeof(timebuf), "%d/%m/%y %H:%M:%S", localtime(&(ww->timestamp)));
191
192 if (ww->type == WHOWAS_RENAME)
193 snprintf(buf, sizeof(buf), "[%s] NICK %s r(%s) -> %s", timebuf, hostmask, np->realname->name->content, ww->newnick->content);
194 else
195 snprintf(buf, sizeof(buf), "[%s] %s %s r(%s): %s", timebuf, (ww->type == WHOWAS_QUIT) ? "QUIT" : "KILL", hostmask, np->realname->name->content, ww->reason->content);
196
197 return buf;
198 }
199
200 const char *whowas_formatchannels(whowas *ww) {
201 static char buf[512];
202 int i, first = 1;
203
204 strcpy(buf, "Channels: ");
205
206 for (i = 0; i < WW_MAXCHANNELS; i++) {
207 if (!ww->channels[i])
208 break;
209
210 if (!first)
211 strncat(buf, ", ", sizeof(buf));
212 else
213 first = 0;
214
215 strncat(buf, ww->channels[i]->name->content, sizeof(buf));
216 }
217
218 if (!ww->channels[0])
219 strncat(buf, "(No channels.)", sizeof(buf));
220
221 buf[sizeof(buf) - 1] = '\0';
222
223 return buf;
224 }
225
226 unsigned int nextwhowasmarker() {
227 whowas *ww;
228 int i;
229 static unsigned int whowasmarker=0;
230
231 whowasmarker++;
232
233 if (!whowasmarker) {
234 /* If we wrapped to zero, zap the marker on all records */
235 for (i = 0; i < whowasmax; i++) {
236 ww = &whowasrecs[i % whowasmax];
237 ww->marker=0;
238 }
239
240 whowasmarker++;
241 }
242
243 return whowasmarker;
244 }
245
246 void _init(void) {
247 {
248 sstring *temp = getcopyconfigitem("whowas", "maxentries", XStringify(WW_DEFAULT_MAXENTRIES), 10);
249 whowasmax = atoi(temp->content);
250 freesstring(temp);
251 }
252 whowasrecs = calloc(whowasmax, sizeof(whowas));
253
254 registerhook(HOOK_NICK_QUIT, whowas_handlequitorkill);
255 registerhook(HOOK_NICK_KILL, whowas_handlequitorkill);
256 registerhook(HOOK_NICK_RENAME, whowas_handlerename);
257 }
258
259 void _fini(void) {
260 int i;
261 whowas *ww;
262
263 deregisterhook(HOOK_NICK_QUIT, whowas_handlequitorkill);
264 deregisterhook(HOOK_NICK_KILL, whowas_handlequitorkill);
265 deregisterhook(HOOK_NICK_RENAME, whowas_handlerename);
266
267 for (i = 0; i < whowasmax; i++) {
268 ww = &whowasrecs[i];
269 whowas_clean(ww);
270 }
271
272 free(whowasrecs);
273 }