added new auth-check security feature
[NeonServV5.git] / src / WHOHandler.c
1 /* WHOHandler.c - NeonServ v5.3
2  * Copyright (C) 2011-2012  Philipp Kreil (pk910)
3  * 
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License 
15  * along with this program. If not, see <http://www.gnu.org/licenses/>. 
16  */
17
18 #include "WHOHandler.h"
19 #include "ChanNode.h"
20 #include "UserNode.h"
21 #include "ChanUser.h"
22 #include "ModeNode.h"
23 #include "ClientSocket.h"
24 #include "IPNode.h"
25
26 #define WHOQUEUETYPE_ISONQUEUE 0x01
27 #define WHOQUEUETYPE_USERLIST  0x02
28 #define WHOQUEUETYPE_USERAUTH  0x04
29 #define WHOQUEUETYPE_CHECKTYPE 0x07
30 #define WHOQUEUETYPE_FOUND     0x08
31
32 #define MAXCALLBACKS 3
33
34 struct WHOQueueEntry {
35     char type;
36     int whoid;
37     struct ChanNode *chan;
38     struct UserNode *user;
39     struct WHOQueueEntry *next;
40     void *callback[MAXCALLBACKS];
41     void *data[MAXCALLBACKS];
42 };
43
44 static int checkWHOID(struct ClientSocket *client, int whoid) {
45     struct WHOQueueEntry *entry;
46     for(entry = client->whoqueue_first; entry; entry = entry->next) {
47         if(entry->whoid == whoid)
48             return 1;
49     }
50     return 0;
51 }
52
53 static struct WHOQueueEntry* addWHOQueueEntry(struct ClientSocket *client) {
54     SYNCHRONIZE(whohandler_sync);
55     int whoid = 0;
56     do {
57         whoid++;
58     } while(checkWHOID(client, whoid) && whoid < 1000);
59     if(whoid == 1000) {
60         DESYNCHRONIZE(whohandler_sync);
61         return NULL;
62     }
63     struct WHOQueueEntry *entry = malloc(sizeof(*entry));
64     if (!entry)
65     {
66         perror("malloc() failed");
67         DESYNCHRONIZE(whohandler_sync);
68         return NULL;
69     }
70     entry->next = NULL;
71     entry->whoid = whoid;
72     if(client->whoqueue_last) {
73         client->whoqueue_last->next = entry;
74     } else {
75         client->whoqueue_first = entry;
76     }
77     client->whoqueue_last = entry;
78     DESYNCHRONIZE(whohandler_sync);
79     return entry;
80 }
81
82 static struct WHOQueueEntry* getNextWHOQueueEntry(struct ClientSocket *client, int whoid, int freeEntry) {
83     if(!client->whoqueue_first) return NULL;
84     SYNCHRONIZE(whohandler_sync);
85     struct WHOQueueEntry *entry;
86     for(entry = client->whoqueue_first; entry; entry = entry->next) {
87         if(entry->whoid == whoid)
88             break;
89     }
90     if(!entry) {
91         DESYNCHRONIZE(whohandler_sync);
92         return NULL;
93     }
94     if(freeEntry) {
95         client->whoqueue_first = entry->next;
96         if(entry == client->whoqueue_last) {
97             client->whoqueue_last = NULL;
98         }
99     }
100     DESYNCHRONIZE(whohandler_sync);
101     return entry;
102 }
103
104 void clear_whoqueue(struct ClientSocket *client) {
105     if(!client->whoqueue_first) return;
106     SYNCHRONIZE(whohandler_sync);
107     struct WHOQueueEntry *entry, *next;
108     for(entry = client->whoqueue_first; entry; entry = next) {
109         next = entry->next;
110         free(entry);
111     }
112     client->whoqueue_last = NULL;
113     client->whoqueue_first = NULL;
114     DESYNCHRONIZE(whohandler_sync);
115 }
116
117 void get_userlist(struct ChanNode *chan, userlist_callback_t callback, void *data) {
118     struct ClientSocket *bot;
119     for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
120         if(isUserOnChan(bot->user, chan))
121             break;
122     }
123     if(bot == NULL) return;
124     //check if we really need to who the channel
125     int do_who = (!(chan->flags & CHANFLAG_RECEIVED_USERLIST));
126     if(!do_who) {
127         struct ChanUser *chanuser;
128         for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
129             if(!(chanuser->user->flags & (USERFLAG_ISAUTHED | USERFLAG_ISIRCOP | USERFLAG_ISBOT)) && (time(0) - chanuser->user->last_who) > REWHO_TIMEOUT) {
130                 do_who = 1;
131                 break;
132             }
133         }
134     }
135     if(do_who) {
136         struct WHOQueueEntry* entry = addWHOQueueEntry(bot);
137         entry->type = WHOQUEUETYPE_ISONQUEUE | WHOQUEUETYPE_USERLIST;
138         entry->chan = chan;
139         entry->callback[0] = callback;
140         int i;
141         for(i = 1; i < MAXCALLBACKS; i++)
142             entry->callback[i] = NULL;
143         entry->data[0] = data;
144         for(i = 1; i < MAXCALLBACKS; i++)
145             entry->data[i] = NULL;
146         putsock(bot, "WHO %s,%d %%tuihnaf,%d", chan->name, entry->whoid, entry->whoid);
147     } else
148         callback(bot, chan, data);
149 }
150
151 void _get_userlist_with_invisible(struct ChanNode *chan, userlist_callback_t callback, void *data, int force) {
152     struct ClientSocket *bot;
153     for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
154         if(isUserOnChan(bot->user, chan))
155             break;
156     }
157     if(bot == NULL) return;
158     //check if we really need to who the channel
159     //invisible users can only be present if chanmode +D or +d is set!
160     int do_who = (!(chan->flags & CHANFLAG_RECEIVED_USERLIST))  || (isModeSet(chan->modes, 'd') || isModeSet(chan->modes, 'D'));
161     if(!do_who && force) {
162         struct ChanUser *chanuser;
163         for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
164             if(!(chanuser->user->flags & (USERFLAG_ISAUTHED | USERFLAG_ISIRCOP | USERFLAG_ISBOT)) && (time(0) - chanuser->user->last_who) > REWHO_TIMEOUT) {
165                 do_who = 1;
166                 break;
167             }
168         }
169     }
170     if(do_who) {
171         struct WHOQueueEntry* entry = addWHOQueueEntry(bot);
172         entry->type = WHOQUEUETYPE_ISONQUEUE | WHOQUEUETYPE_USERLIST;
173         entry->chan = chan;
174         entry->callback[0] = callback;
175         int i;
176         for(i = 1; i < MAXCALLBACKS; i++)
177             entry->callback[i] = NULL;
178         entry->data[0] = data;
179         for(i = 1; i < MAXCALLBACKS; i++)
180             entry->data[i] = NULL;
181         putsock(bot, "WHO %s,%d d%%tuihnaf,%d", chan->name, entry->whoid, entry->whoid);
182     } else
183         callback(bot, chan, data);
184 }
185
186 void get_userauth(struct UserNode *user, userauth_callback_t callback, void *data) {
187     //check if we have already an active WHO for this user
188     struct ClientSocket *bot, *whobot = NULL;
189     struct WHOQueueEntry *entry;
190     for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
191         for(entry = bot->whoqueue_first; entry; entry = entry->next) {
192             if((entry->type & WHOQUEUETYPE_USERAUTH) && entry->user == user) {
193                 int i = 0;
194                 for(i = 1; i < MAXCALLBACKS; i++) {
195                     if(!entry->callback[i]) {
196                         entry->callback[i] = callback;
197                         entry->data[i] = data;
198                         return;
199                     }
200                 }
201             }
202         }
203         if(bot->flags & SOCKET_FLAG_PREFERRED)
204             whobot = bot;
205     }
206     bot = whobot;
207     if(bot == NULL) bot = getBots(SOCKET_FLAG_READY, NULL);
208     //check if we really need to who the user
209     if(!is_valid_nick(user->nick)) {
210         callback(bot, user->nick, NULL, data);
211         return;
212     }
213     if((user->flags & (USERFLAG_ISAUTHED | USERFLAG_ISIRCOP | USERFLAG_ISBOT | USERFLAG_ISSERVER)) || (time(0) - user->last_who) <= REWHO_TIMEOUT) {
214         callback(bot, user->nick, user, data);
215         return;
216     }
217     entry = addWHOQueueEntry(bot);
218     entry->type = WHOQUEUETYPE_ISONQUEUE | WHOQUEUETYPE_USERAUTH;
219     entry->user = user;
220     user->flags |= USERFLAG_IS_ON_WHO_QUEUE;
221     entry->callback[0] = callback;
222     int i;
223     for(i = 1; i < MAXCALLBACKS; i++)
224         entry->callback[i] = NULL;
225     entry->data[0] = data;
226     for(i = 1; i < MAXCALLBACKS; i++)
227             entry->data[i] = NULL;
228     //WHO ".$user->getNick().",".$id." %tuhna,".$id
229     putsock(bot, "WHO %s,%d %%tuhna,%d", user->nick, entry->whoid, entry->whoid);
230 }
231
232 static void _recv_whohandler_354(struct ClientSocket *client, char **argv, unsigned int argc);
233 void recv_whohandler_354(struct ClientSocket *client, char **argv, unsigned int argc) {
234     _recv_whohandler_354(client, argv, argc);
235 }
236
237 static void _recv_whohandler_354(struct ClientSocket *client, char **argv, unsigned int argc) {
238     int i;
239     if(argc < 2) return;
240     int type = atoi(argv[1]);
241     if(!type) return;
242     struct WHOQueueEntry* entry = getNextWHOQueueEntry(client, type, 0);
243     if(entry == NULL) return;
244     #ifdef HAVE_THREADS
245     unsigned long tid = syscall(SYS_gettid);
246     while(!clientsocket_parseorder_top(tid)) {
247         usleep(1000); //1ms
248     }
249     #endif
250     if(entry->type & WHOQUEUETYPE_USERLIST) {
251         if(argc < 7) return;
252         //:OGN2.OnlineGamesNet.net 354 skynet 1 pk910 2001:41d0:2:1d3b::babe skynet H@ pk910
253         struct ChanNode *chan = entry->chan;
254         //add the user toe the channel if he isn't added, yet and update its user data
255         //parse flags
256         int userflags = 0;
257         int chanuserflags = 0;
258         for(i = 0; i < strlen(argv[6]); i++) {
259             switch (argv[6][i]) {
260                 case '@':
261                     chanuserflags |= CHANUSERFLAG_OPPED;
262                     break;
263                 case '%':
264                     chanuserflags |= CHANUSERFLAG_HALFOPPED;
265                     break;
266                 case '+':
267                     chanuserflags |= CHANUSERFLAG_VOICED;
268                     break;
269                 case '*':
270                     userflags |= USERFLAG_ISIRCOP;
271                     break;
272                 case '<':
273                     chanuserflags |= CHANUSERFLAG_INVISIBLE;
274                     break;
275                 default:
276                     break;
277             }
278         }
279         
280         struct UserNode *user = getUserByNick(argv[5]);
281         struct ChanUser *chanuser;
282         if((chanuserflags & CHANUSERFLAG_INVISIBLE)) {
283             if(!user) {
284                 user = createTempUser(argv[5]);
285                 user->flags |= USERFLAG_ISTMPUSER;
286             }
287             chan->flags |= CHANFLAG_HAVE_INVISIBLES;
288             chanuser = addInvisibleChanUser(chan, user);
289             chanuser->flags = (chanuser->flags & ~CHANUSERFLAG_OPPED_OR_VOICED) | chanuserflags;
290         } else {
291             if(user == NULL) {
292                 user = addUser(argv[5]);
293             }
294             if(!(chanuser = getChanUser(user, chan))) {
295                 chanuser = addChanUser(chan, user);
296             }
297             chanuser->flags = (chanuser->flags & ~(CHANUSERFLAG_OPPED_OR_VOICED | CHANUSERFLAG_INVISIBLE)) | chanuserflags;
298         }
299         user->flags = (user->flags & ~USERFLAG_ISIRCOP) | userflags;
300         user->last_who = time(0);
301         if(!*user->ident)
302             strcpy(user->ident, argv[2]);
303         if(!user->ip)
304             user->ip = createIPNode(argv[3]);
305         if(!*user->host)
306             strcpy(user->host, argv[4]);
307         if(!(user->flags & USERFLAG_ISAUTHED) && strcmp(argv[7], "0")) {
308             strcpy(user->auth, argv[7]);
309             user->flags |= USERFLAG_ISAUTHED;
310         }
311     } else if((entry->type & WHOQUEUETYPE_USERAUTH) && !(entry->type & WHOQUEUETYPE_FOUND)) {
312         //:OGN2.OnlineGamesNet.net 354 Skynet 1 pk910 2001:41d0:2:1d3b::babe Skynet pk910
313         entry->type |= WHOQUEUETYPE_FOUND;
314         entry->user->last_who = time(0);
315         if(strcmp(argv[5], "0") && !(entry->user->flags & USERFLAG_ISAUTHED)) {
316             strcpy(entry->user->auth, argv[5]);
317             entry->user->flags |= USERFLAG_ISAUTHED;
318         }
319         for(i = 0; i < MAXCALLBACKS; i++) {
320             userauth_callback_t *callback = entry->callback[i];
321             if(!callback) break;
322             callback(client, entry->user->nick, entry->user, entry->data[i]);
323         }
324     }
325 }
326
327 static void _recv_whohandler_315(struct ClientSocket *client, char **argv, unsigned int argc);
328 void recv_whohandler_315(struct ClientSocket *client, char **argv, unsigned int argc) {
329     _recv_whohandler_315(client, argv, argc);
330 }
331
332 static void _recv_whohandler_315(struct ClientSocket *client, char **argv, unsigned int argc) {
333     if(argc < 2) return;
334     char *typestr = strstr(argv[1], ",");
335     if(!typestr) return;
336     typestr++;
337     int type = atoi(typestr);
338     struct WHOQueueEntry* entry = getNextWHOQueueEntry(client, type, 0);
339     if(entry == NULL) return;
340     #ifdef HAVE_THREADS
341     unsigned long tid = syscall(SYS_gettid);
342     while(!clientsocket_parseorder_top(tid)) {
343         usleep(1000); //1ms
344     }
345     #endif
346     getNextWHOQueueEntry(client, type, 1);
347     if(entry->type & WHOQUEUETYPE_USERLIST) {
348         //:OGN2.OnlineGamesNet.net 315 skynet #pk910,1 :End of /WHO list.
349         entry->chan->flags |= CHANFLAG_RECEIVED_USERLIST;
350         userlist_callback_t *callback;
351         int i;
352         for(i = 0; i < MAXCALLBACKS; i++) {
353             callback = entry->callback[i];
354             if(!callback) break;
355             callback(client, entry->chan, entry->data[i]);
356         }
357         if(entry->chan->flags & CHANFLAG_HAVE_INVISIBLES) {
358             //remove all invisible users again
359             struct ChanUser *chanuser, *next;
360             for(chanuser = getChannelUsers(entry->chan, NULL); chanuser; chanuser = next) {
361                 next = getChannelUsers(entry->chan, chanuser);
362                 if((chanuser->flags & CHANUSERFLAG_INVISIBLE) && !isBot(chanuser->user)) {
363                     delChanUser(chanuser, 1);
364                 }
365             }
366         }
367     } else if(entry->type & WHOQUEUETYPE_USERAUTH) {
368         if(!(entry->type & WHOQUEUETYPE_FOUND)) {
369             userauth_callback_t *callback;
370             int i;
371             for(i = 0; i < MAXCALLBACKS; i++) {
372                 callback = entry->callback[i];
373                 if(!callback) break;
374                 callback(client, entry->user->nick, NULL, entry->data[i]);
375             }
376         }
377         entry->user->flags &= ~USERFLAG_IS_ON_WHO_QUEUE;
378         if(entry->user->flags & USERFLAG_FREE_AFTER_WHO) {
379             delUser(entry->user, 1);
380         }
381     }
382     free(entry);
383 }
384
385 void free_whoqueue() {
386     
387 }