ircu2.10.12 pk910 fork
[ircu2.10.12-pk.git] / ircd / m_webirc.c
1 /*
2  * IRC - Internet Relay Chat, ircd/m_svsnick.c
3  * Written by David Herrmann.
4  */
5
6 #include "config.h"
7
8 #include "client.h"
9 #include "hash.h"
10 #include "ircd.h"
11 #include "ircd_alloc.h"
12 #include "ircd_log.h"
13 #include "ircd_reply.h"
14 #include "ircd_string.h"
15 #include "ircd_features.h"
16 #include "ircd_crypt.h"
17 #include "numeric.h"
18 #include "numnicks.h"
19 #include "send.h"
20 #include "s_conf.h"
21 #include "s_misc.h"
22 #include "s_debug.h"
23 #include "match.h"
24 #include "IPcheck.h"
25 #include "ssl.h"
26 #include "res.h"
27
28 #include <stdlib.h>
29 #include <string.h>
30 #include <stdio.h>
31
32 /* Sends response \r (len: \l) to client \c. */
33 #define webirc_resp(c, r, l) \
34    ssl_send(cli_fd(c), cli_socket(c).ssl, r, l)
35
36 /* Buffer used in nick replacements. */
37 static char webirc_buf[513];
38
39 /* Returns 1 if the passwords are the same and 0 if not.
40  * \to_match is the password hash
41  * \passwd is the unhashed password in "$KIND$password" style
42  */
43 static unsigned int webirc_pwmatch(const char* to_match, const char* passwd) {
44     char *crypted;
45     signed int res;
46
47     crypted = ircd_crypt(to_match, passwd);
48     if(!crypted)
49         return 0;
50     Debug((DEBUG_NOTICE, "WebIRC: Passwort check: %s = %s", crypted, passwd));
51     res = strcmp(crypted, passwd);
52     MyFree(crypted);
53     return 0 == res;
54 }
55
56 /* Checks whether password/host/spoofed host/ip are allowed and returns the corresponding webirc block.
57  * Returns NULL if nothing found.
58  */
59 static struct webirc_block *webirc_match(const char *passwd, const char *real_host, const char *real_ip, const char *spoofed_host, const char *spoofed_ip) {
60     struct webirc_block *iter;
61     struct webirc_node *inode;
62     unsigned int matched = 0;
63
64     if(!GlobalWebIRCConf) {
65         Debug((DEBUG_NOTICE, "WebIRC: no global webirc conf"));
66         return NULL;
67     }
68
69     iter = GlobalWebIRCConf;
70     do {
71         if(iter->list) {
72             inode = iter->list;
73
74             /* first check for matching password */
75             do {
76                 /* it's a sorted list an passwords are stored first! */
77
78                 if(inode->type != WEBIRC_PASS) break;
79                 Debug((DEBUG_NOTICE, "WebIRC: pass: %s",inode->content));
80                 if(webirc_pwmatch(passwd, inode->content)) {
81                     matched = 1;
82                     break;
83                 }
84
85                 inode = inode->next;
86             } while(inode != iter->list);
87
88             /* go to next entry */
89             inode = inode->next;
90
91             if(!matched)
92                 Debug((DEBUG_NOTICE, "WebIRC: Password missmatch"));
93
94             /* check for matching real-host/ip */
95             if(matched) {
96                 matched = 0;
97                 /* fast-forward to hosts and then check the hosts */
98                 do {
99                     /* everything greater than WEBIRC_HOSTS are the spoofed masks */
100                     if(inode->type > WEBIRC_HOST) break;
101
102                     if(inode->type == WEBIRC_HOST) {
103                         if(inode->neg) {
104                             if(match(inode->content, real_host) == 0 || match(inode->content, real_ip) == 0) {
105                                 matched = 0;
106                                 break;
107                             }
108                         }
109                         else if(matched) /* do nothing */;
110                         else if(match(inode->content, real_host) == 0 || match(inode->content, real_ip) == 0)
111                             matched = 1;
112                     }
113
114                     inode = inode->next;
115                 } while(inode != iter->list);
116                 if(!matched)
117                     Debug((DEBUG_NOTICE, "WebIRC: host missmatch"));
118             }
119
120             /* check for matching spoofed host/ip */
121             if(matched) {
122                 matched = 0;
123                 do {
124                     if(inode->type == WEBIRC_SPOOF) {
125                         if(inode->neg) {
126                             if(match(inode->content, spoofed_host) == 0 || match(inode->content, spoofed_ip) == 0) {
127                                 matched = 0;
128                                 break;
129                             }
130                         }
131                         else if(matched) /* do nothing */;
132                         else if(match(inode->content, spoofed_host) == 0 || match(inode->content, spoofed_ip) == 0)
133                             matched = 1;
134                     }
135
136                     inode = inode->next;
137                 } while(inode != iter->list);
138                 if(!matched)
139                     Debug((DEBUG_NOTICE, "WebIRC: spoof missmatch"));
140             }
141
142             if(matched) return iter;
143
144             /* nothing found, try next block */
145         }
146         iter = iter->next;
147     } while(iter != GlobalWebIRCConf);
148
149     return NULL;
150 }
151
152 /*
153  * m_webirc
154  *
155  * parv[0] = sender prefix
156  * parv[1] = password
157  * parv[2] = "cgiirc"
158  * parv[3] = hostname
159  * parv[4] = ip
160  */
161 int m_webirc(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) {
162     struct webirc_block *block;
163     struct irc_in_addr addr;
164     const char *con_addr;
165     time_t next_target = 0;
166     unsigned int len;
167
168     const char *nick = (*(cli_name(sptr))) ? cli_name(sptr) : "AUTH";
169     unsigned int auth = (*(cli_name(sptr))) ? 0 : 1;
170
171     /* servers cannot spoof their ip */
172     if(IsServerPort(sptr)) {
173         /* If a server sends WEBIRC command it's a protocol violation so exit him and do not check FEAT_WEBIRC_REJECT. */
174         IPcheck_connect_fail(sptr);
175         return exit_client(cptr, sptr, &me, "WebIRC not supported on server ports");
176     }
177
178     /* all 4 parameters are required plus the prefix => 5 */
179     if(parc < 5)
180         return need_more_params(sptr, "WEBIRC");
181
182     if(strcmp(parv[2], "cgiirc")) {
183         if(feature_bool(FEAT_WEBIRC_REJECT)) {
184             IPcheck_connect_fail(sptr);
185             return exit_client(cptr, sptr, &me, "WebIRC protocol violation (p2).");
186         }
187         else {
188             len = sprintf(webirc_buf, "NOTICE %s :%sWebIRC protocol violation (p2).\r\n", nick, auth ? "*** " : "");
189             webirc_resp(sptr, webirc_buf, len);
190             return 0; /* continue with normal authentication */
191         }
192     }
193
194     /* created ip in dotted notation */
195     con_addr = ircd_ntoa(&(cli_ip(sptr)));
196     if(0 == ipmask_parse(parv[4], &addr, NULL)) {
197         if(feature_bool(FEAT_WEBIRC_REJECT)) {
198             IPcheck_connect_fail(sptr);
199             return exit_client(cptr, sptr, &me, "WebIRC protocol violation (p4).");
200         }
201         else {
202             /* bufferoverflow prevented with NICKLEN check above */
203             len = sprintf(webirc_buf, "NOTICE %s :%sWebIRC protocol violation (p4).\r\n", nick, auth ? "*** " : "");
204             webirc_resp(sptr, webirc_buf, len);
205             return 0; /* continue with normal authentication */
206         }
207     }
208
209     /* find matching webirc block */
210     block = webirc_match(parv[1], cli_sockhost(sptr), con_addr, parv[3], parv[4]);
211     if(!block) {
212         if(feature_bool(FEAT_WEBIRC_REJECT)) {
213             IPcheck_connect_fail(sptr);
214             return exit_client(cptr, sptr, &me, "WebIRC client rejected, no match found.");
215         }
216         else {
217             len = sprintf(webirc_buf, "NOTICE %s :%sWebIRC spoofing rejected, no match found.\r\n", nick, auth?"*** ":"");
218             webirc_resp(sptr, webirc_buf, len);
219             return 0; /* continue with normal authentication */
220         }
221     }
222
223     /* remove the WebIRC ip from the IPcheck entry, we will add the real one later */
224     IPcheck_connect_fail(sptr);
225     IPcheck_disconnect(sptr);
226     ClearIPChecked(sptr);
227
228     /* spoof IP */
229     memcpy(cli_real_ip(sptr).in6_16, cli_ip(sptr).in6_16, 16);
230     memcpy(cli_ip(sptr).in6_16, addr.in6_16, 16);
231
232     /* spoof ip/host strings */
233     ircd_strncpy(cli_real_sock_ip(sptr), cli_sock_ip(sptr), SOCKIPLEN);
234     ircd_strncpy(cli_sock_ip(sptr), parv[4], SOCKIPLEN);
235     ircd_strncpy(cli_real_sockhost(sptr), cli_sockhost(sptr), HOSTLEN);
236     ircd_strncpy(cli_sockhost(sptr), parv[3], HOSTLEN);
237     ircd_strncpy(cli_webirc(sptr), block->name, NICKLEN);
238
239     /* add the real ip to the IPcheck */
240     if(!IPcheck_local_connect(&cli_ip(sptr), &next_target))
241         return exit_client(cptr, sptr, &me, "Too many connections from your host");
242     SetIPChecked(cptr);
243
244     /* set WebIRC umode only if enabled */
245     if(feature_bool(FEAT_WEBIRC_UMODE))
246         SetWebIRC(cptr);
247
248     return 0;
249 }
250