added new auth-check security feature
[NeonServV5.git] / src / HandleInfoHandler.c
1 /* HandleInfoHandler.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 "HandleInfoHandler.h"
19 #include "ClientSocket.h"
20 #include "UserNode.h"
21 #include "ChanNode.h"
22 #include "IRCEvents.h"
23 #include "tools.h"
24
25 #define AUTHSERV_NICK "AuthServ"
26
27 #define MAXCALLBACKS 3
28
29 struct HandleInfoQueueEntry {
30     char *auth;
31     void *callback[MAXCALLBACKS];
32     void *data[MAXCALLBACKS];
33     
34     struct HandleInfoQueueEntry *next;
35 };
36
37 static struct HandleInfoQueueEntry* addHandleInfoQueueEntry(struct ClientSocket *client) {
38     struct HandleInfoQueueEntry *entry = malloc(sizeof(*entry));
39     if (!entry)
40     {
41         perror("malloc() failed");
42         return NULL;
43     }
44     SYNCHRONIZE(cache_sync);
45     entry->next = NULL;
46     if(client->handleinfo_last)
47         client->handleinfo_last->next = entry;
48     else
49         client->handleinfo_first = entry;
50     client->handleinfo_last = entry;
51     DESYNCHRONIZE(cache_sync);
52     return entry;
53 }
54
55 static struct HandleInfoQueueEntry* getNextHandleInfoQueueEntry(struct ClientSocket *client, int freeEntry) {
56     if(!client->handleinfo_first) return NULL;
57     SYNCHRONIZE(cache_sync);
58     struct HandleInfoQueueEntry *entry = client->handleinfo_first;
59     if(freeEntry) {
60         client->handleinfo_first = entry->next;
61         if(entry == client->handleinfo_last) {
62             client->handleinfo_last = NULL;
63         }
64     }
65     DESYNCHRONIZE(cache_sync);
66     return entry;
67 }
68
69 void clear_handleinfoqueue(struct ClientSocket *client) {
70     if(!client->handleinfo_first) return;
71     SYNCHRONIZE(cache_sync);
72     struct HandleInfoQueueEntry *entry, *next;
73     for(entry = client->handleinfo_first; entry; entry = next) {
74         next = entry->next;
75         free(entry);
76     }
77     client->handleinfo_last = NULL;
78     client->handleinfo_first = NULL;
79     DESYNCHRONIZE(cache_sync);
80 }
81
82 void lookup_authname(char *auth, authlookup_callback_t callback, void *data) {
83     struct ClientSocket *bot;
84     struct HandleInfoQueueEntry* entry;
85     for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
86         for(entry = bot->handleinfo_first; entry; entry = entry->next) {
87             if(!stricmp(entry->auth, auth)) {
88                 int i = 0;
89                 for(i = 1; i < MAXCALLBACKS; i++) {
90                     if(!entry->callback[i]) {
91                         entry->callback[i] = callback;
92                         entry->data[i] = data;
93                         return;
94                     }
95                 }
96             }
97         }
98         if(bot->flags & SOCKET_FLAG_PREFERRED)
99             break;
100     }
101     if(bot == NULL) return;
102     entry = addHandleInfoQueueEntry(bot);
103     int i;
104     entry->auth = strdup(auth);
105     entry->callback[0] = callback;
106     for(i = 1; i < MAXCALLBACKS; i++)
107         entry->callback[i] = NULL;
108     entry->data[0] = data;
109     for(i = 1; i < MAXCALLBACKS; i++)
110         entry->data[i] = NULL;
111     putsock(bot, "PRIVMSG " AUTHSERV_NICK " :ACCOUNTINFO *%s", auth);
112 }
113
114 static void recv_notice(struct UserNode *user, struct UserNode *target, char *message) {
115     if(stricmp(user->nick, AUTHSERV_NICK)) return;
116     struct ClientSocket *bot;
117     for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
118         if(bot->user == target) break;
119     }
120     if(!bot) return;
121     char *auth = NULL;
122     int do_match = 0, exists = 0;
123     char *tmp;
124     time_t registered = time(0);
125     struct tm *timeinfo;
126     //messages to parse:
127     //  Account * has not been registered.
128     //  Account information for Skynet:
129     if(!match("Account * has not been registered.", message)) {
130         do_match = 1;
131         tmp = strstr(message, "\002");
132         auth = tmp+1;
133         tmp = strstr(auth, "\002");
134         *tmp = '\0';
135     } else if(!match("Account information for *", message)) {
136         do_match = 2;
137         exists = 1;
138         tmp = strstr(message, "\002");
139         auth = tmp+1;
140         tmp = strstr(auth, "\002");
141         *tmp = '\0';
142     } else if(!match("  Registered on: *", message)) {
143         do_match = 1;
144         exists = 1;
145         tmp = strstr(message, ": ");
146         tmp += 2;
147         timeinfo = localtime(&registered);
148         timeinfo->tm_year = 0;
149         //parse time
150         //Sat Nov 19 14:52:57 2011
151         tmp = strchr(tmp, ' ');
152         if(!tmp) goto errparse;
153         tmp++;
154         char *tmp2 = strchr(tmp, ' ');
155         if(!tmp2) goto errparse;
156         *tmp2 = '\0';
157         if(!stricmp(tmp, "Jan"))
158             timeinfo->tm_mon = 0;
159         else if(!stricmp(tmp, "Feb"))
160             timeinfo->tm_mon = 1;
161         else if(!stricmp(tmp, "Mar"))
162             timeinfo->tm_mon = 2;
163         else if(!stricmp(tmp, "Apr"))
164             timeinfo->tm_mon = 3;
165         else if(!stricmp(tmp, "May"))
166             timeinfo->tm_mon = 4;
167         else if(!stricmp(tmp, "Jun"))
168             timeinfo->tm_mon = 5;
169         else if(!stricmp(tmp, "Jul"))
170             timeinfo->tm_mon = 6;
171         else if(!stricmp(tmp, "Aug"))
172             timeinfo->tm_mon = 7;
173         else if(!stricmp(tmp, "Sep"))
174             timeinfo->tm_mon = 8;
175         else if(!stricmp(tmp, "Oct"))
176             timeinfo->tm_mon = 9;
177         else if(!stricmp(tmp, "Nov"))
178             timeinfo->tm_mon = 10;
179         else if(!stricmp(tmp, "Dec"))
180             timeinfo->tm_mon = 11;
181         tmp = tmp2 + 1;
182         tmp2 = strchr(tmp, ' ');
183         if(!tmp2) goto errparse;
184         *tmp2 = '\0';
185         timeinfo->tm_mday = atoi(tmp);
186         tmp = tmp2 + 1;
187         if(*tmp == ' ') tmp++;
188         tmp2 = strchr(tmp, ':');
189         if(!tmp2) goto errparse;
190         *tmp2 = '\0';
191         timeinfo->tm_hour = atoi(tmp);
192         tmp = tmp2 + 1;
193         tmp2 = strchr(tmp, ':');
194         if(!tmp2) goto errparse;
195         *tmp2 = '\0';
196         timeinfo->tm_min = atoi(tmp);
197         tmp = tmp2 + 1;
198         tmp2 = strchr(tmp, ' ');
199         if(!tmp2) goto errparse;
200         *tmp2 = '\0';
201         timeinfo->tm_sec = atoi(tmp);
202         tmp = tmp2 + 1;
203         timeinfo->tm_year = atoi(tmp) - 1900;
204         registered = mktime(timeinfo);
205     }
206     errparse:
207     
208     if(do_match) {
209         #ifdef HAVE_THREADS
210         unsigned long tid = syscall(SYS_gettid);
211         while(!clientsocket_parseorder_top(tid)) {
212             usleep(1000); //1ms
213         }
214         #endif
215         struct HandleInfoQueueEntry* entry = getNextHandleInfoQueueEntry(bot, ((do_match != 2) ? 1 : 0));
216         if(entry) {
217             if(do_match == 2) {
218                 free(entry->auth);
219                 entry->auth = strdup(auth);
220                 return;
221             }
222             authlookup_callback_t *callback;
223             int i;
224             for(i = 0; i < MAXCALLBACKS; i++) {
225                 callback = entry->callback[i];
226                 if(!callback) break;
227                 callback(entry->auth, exists, registered, entry->data[i]);
228             }
229             free(entry->auth);
230             free(entry);
231         }
232     }
233 }
234
235 void init_handleinfohandler() {
236     bind_privnotice(recv_notice);
237 }
238
239 void free_handleinfohandler() {
240     
241 }