Author: Bleep <tomh@inxpress.net>
[ircu2.10.12-pk.git] / ircd / m_connect.c
1 /*
2  * IRC - Internet Relay Chat, ircd/m_connect.c
3  * Copyright (C) 1990 Jarkko Oikarinen and
4  *                    University of Oulu, Computing Center
5  *
6  * See file AUTHORS in IRC package for additional names of
7  * the programmers.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 1, or (at your option)
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  *
23  * $Id$
24  */
25
26 /*
27  * m_functions execute protocol messages on this server:
28  *
29  *    cptr    is always NON-NULL, pointing to a *LOCAL* client
30  *            structure (with an open socket connected!). This
31  *            identifies the physical socket where the message
32  *            originated (or which caused the m_function to be
33  *            executed--some m_functions may call others...).
34  *
35  *    sptr    is the source of the message, defined by the
36  *            prefix part of the message if present. If not
37  *            or prefix not found, then sptr==cptr.
38  *
39  *            (!IsServer(cptr)) => (cptr == sptr), because
40  *            prefixes are taken *only* from servers...
41  *
42  *            (IsServer(cptr))
43  *                    (sptr == cptr) => the message didn't
44  *                    have the prefix.
45  *
46  *                    (sptr != cptr && IsServer(sptr) means
47  *                    the prefix specified servername. (?)
48  *
49  *                    (sptr != cptr && !IsServer(sptr) means
50  *                    that message originated from a remote
51  *                    user (not local).
52  *
53  *            combining
54  *
55  *            (!IsServer(sptr)) means that, sptr can safely
56  *            taken as defining the target structure of the
57  *            message in this server.
58  *
59  *    *Always* true (if 'parse' and others are working correct):
60  *
61  *    1)      sptr->from == cptr  (note: cptr->from == cptr)
62  *
63  *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
64  *            *cannot* be a local connection, unless it's
65  *            actually cptr!). [MyConnect(x) should probably
66  *            be defined as (x == x->from) --msa ]
67  *
68  *    parc    number of variable parameter strings (if zero,
69  *            parv is allowed to be NULL)
70  *
71  *    parv    a NULL terminated list of parameter pointers,
72  *
73  *                    parv[0], sender (prefix string), if not present
74  *                            this points to an empty string.
75  *                    parv[1]...parv[parc-1]
76  *                            pointers to additional parameters
77  *                    parv[parc] == NULL, *always*
78  *
79  *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
80  *                    non-NULL pointers.
81  */
82 #if 0
83 /*
84  * No need to include handlers.h here the signatures must match
85  * and we don't need to force a rebuild of all the handlers everytime
86  * we add a new one to the list. --Bleep
87  */
88 #include "handlers.h"
89 #endif /* 0 */
90 #include "client.h"
91 #include "crule.h"
92 #include "hash.h"
93 #include "ircd.h"
94 #include "ircd_log.h"
95 #include "ircd_reply.h"
96 #include "ircd_string.h"
97 #include "match.h"
98 #include "msg.h"
99 #include "numeric.h"
100 #include "numnicks.h"
101 #include "s_bsd.h"
102 #include "s_conf.h"
103 #include "s_user.h"
104 #include "send.h"
105
106 #include <assert.h>
107 #include <stdlib.h>
108
109 /*
110  * ms_connect - server message handler
111  * - Added by Jto 11 Feb 1989
112  *
113  *    parv[0] = sender prefix
114  *    parv[1] = servername
115  *    parv[2] = port number
116  *    parv[3] = remote server
117  */
118 int ms_connect(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
119 {
120   unsigned short   port;
121   unsigned short   tmpport;
122   const char*      crule_name;
123   struct ConfItem* aconf;
124   struct Client*   acptr;
125   
126   assert(0 != cptr);
127   assert(0 != sptr);
128
129   if (!IsPrivileged(sptr))
130     return send_error_to_client(sptr, ERR_NOPRIVILEGES);
131
132   if (parc < 4) {
133     /*
134      * this is coming from a server which should have already
135      * checked it's args, if we don't have parc == 4, something
136      * isn't right.
137      */
138     return need_more_params(sptr, "CONNECT");
139   }
140
141   if (hunt_server(1, cptr, sptr,
142                   "%s%s " TOK_CONNECT " %s %s :%s", 3, parc, parv) != HUNTED_ISME)
143     return 0;
144
145   /*
146    * need to find the conf entry first so we can use the server name from
147    * the conf entry instead of parv[1] to find out if the server is already
148    * present below. --Bleep
149    */
150   if (0 == (aconf = conf_find_server(parv[1]))) {
151     sendto_one(sptr, "%s NOTICE %s%s :Connect: Host %s not listed in ircd.conf",
152                NumServ(&me), NumNick(sptr), parv[1]);
153     return 0;
154   }
155   /*
156    * use aconf->name to look up the server
157    */
158   if ((acptr = FindServer(aconf->name))) {
159     sendto_one(sptr, "%s NOTICE %s%s :Connect: Server %s %s %s.",
160                NumServ(&me), NumNick(sptr), parv[1], "already exists from",
161                acptr->from->name);
162     return 0;
163   }
164   /*
165    * Evaluate connection rules...  If no rules found, allow the
166    * connect.   Otherwise stop with the first true rule (ie: rules
167    * are ored together.  Oper connects are effected only by D
168    * lines (CRULEALL) not d lines (CRULEAUTO).
169    */
170   if ((crule_name = conf_eval_crule(aconf))) {
171     sendto_one(sptr, "%s NOTICE %s%s :Connect: Disallowed by rule: %s",
172                NumServ(&me), NumNick(sptr), crule_name);
173     return 0;
174   }
175   /*
176    * Get port number from params, port must be non-zero if it comes from a
177    * server.
178    */
179   if ((port = atoi(parv[2])) == 0) {
180     sendto_one(sptr, "%s NOTICE %s%s :Connect: Invalid port number",
181                NumServ(&me), NumNick(sptr));
182     return 0;
183   }
184   /*
185    * save the old port
186    */
187   tmpport = aconf->port;
188   aconf->port = port;
189   /*
190    * Notify all operators about remote connect requests
191    */
192   sendto_ops_butone(0, &me, ":%s WALLOPS :Remote CONNECT %s %s from %s",
193                     me.name, parv[1], parv[2] ? parv[2] : "", 
194                     get_client_name(sptr, HIDE_IP));
195   ircd_log(L_INFO, "CONNECT From %s : %s %d", parv[0], parv[1], parv[2] ? parv[2] : "");
196
197   if (connect_server(aconf, sptr, 0)) {
198     sendto_one(sptr, "%s NOTICE %s%s :*** Connecting to %s.",
199                NumServ(&me), NumNick(sptr), aconf->name);
200   }
201   else {
202     sendto_one(sptr, "%s NOTICE %s%s :*** Connection to %s failed",
203                NumServ(&me), NumNick(sptr), aconf->name);
204   }
205   aconf->port = tmpport;
206   return 0;
207 }
208
209 /*
210  * mo_connect - oper message handler
211  * - Added by Jto 11 Feb 1989
212  *
213  *    parv[0] = sender prefix
214  *    parv[1] = servername
215  *    parv[2] = port number
216  *    parv[3] = remote server
217  */
218 int mo_connect(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
219 {
220   unsigned short   port;
221   unsigned short   tmpport;
222   const char*      crule_name;
223   struct ConfItem* aconf;
224   struct Client*   acptr;
225
226   assert(0 != cptr);
227   assert(cptr == sptr);
228   assert(IsAnOper(sptr));
229
230   if (parc < 2)
231     return need_more_params(sptr, "CONNECT");
232
233   if (parc > 3) {
234     /*
235      * if parc > 3, we are trying to connect two remote
236      * servers to each other
237      */
238     if (IsLocOp(sptr)) {
239       /*
240        * Only allow LocOps to make local CONNECTS --SRB
241        */
242       return 0;
243     }
244     else {
245       struct Client* acptr2;
246       struct Client* acptr3;
247
248       if (!(acptr3 = find_match_server(parv[3]))) {
249         send_error_to_client(sptr, ERR_NOSUCHSERVER, parv[3]);
250         return 0;
251       }
252
253       /*
254        * Look for closest matching server 
255        * needed for "/connect blah 4400 *"?
256        */
257       for (acptr2 = acptr3; acptr2 != &me; acptr2 = acptr2->serv->up) {
258         if (!match(parv[3], acptr2->name))
259           acptr3 = acptr2;
260       }
261       parv[3] = acptr3->name;
262       if (hunt_server(1, cptr, sptr, "%s%s " TOK_CONNECT " %s %s :%s",
263                       3, parc, parv) != HUNTED_ISME)
264         return 0;
265     }
266   }
267   /*
268    * need to find the conf entry first so we can use the server name from
269    * the conf entry instead of parv[1] to find out if the server is already
270    * present below. --Bleep
271    */
272   if (0 == (aconf = conf_find_server(parv[1]))) {
273     sendto_one(sptr,
274                ":%s NOTICE %s :Connect: Host %s not listed in ircd.conf",
275                me.name, parv[0], parv[1]);
276     return 0;
277   }
278   /*
279    * use aconf->name to look up the server, see above
280    */
281   if ((acptr = FindServer(aconf->name))) {
282     sendto_one(sptr, ":%s NOTICE %s :Connect: Server %s %s %s.",
283                me.name, parv[0], parv[1], "already exists from",
284                acptr->from->name);
285     return 0;
286   }
287   /*
288    * Evaluate connection rules...  If no rules found, allow the
289    * connect.   Otherwise stop with the first true rule (ie: rules
290    * are ored together.  Oper connects are effected only by D
291    * lines (CRULEALL) not d lines (CRULEAUTO).
292    */
293   if ((crule_name = conf_eval_crule(aconf))) {
294     sendto_one(sptr, ":%s NOTICE %s :Connect: Disallowed by rule: %s",
295                me.name, parv[0], crule_name);
296     return 0;
297   }
298   /*
299    *  Get port number from user, if given. If not specified,
300    *  use the default from configuration structure. If missing
301    *  from there, then use the precompiled default.
302    */
303   port = aconf->port;
304   if (parc > 2) {
305     assert(0 != parv[2]);
306     if (0 == (port = atoi(parv[2]))) {
307       sendto_one(sptr, ":%s NOTICE %s :Connect: Invalid port number",
308                  me.name, parv[0]);
309       return 0;
310     }
311   }
312   if (0 == port && 0 == (port = SERVER_PORT)) {
313     sendto_one(sptr, ":%s NOTICE %s :Connect: missing port number",
314                me.name, parv[0]);
315     return 0;
316   }
317
318   tmpport = aconf->port;
319   aconf->port = port;
320
321   if (connect_server(aconf, sptr, 0)) {
322     sendto_one(sptr, ":%s NOTICE %s :*** Connecting to %s.",
323                me.name, parv[0], aconf->name);
324   }
325   else {
326     sendto_one(sptr, ":%s NOTICE %s :*** Connection to %s failed",
327                me.name, parv[0], aconf->name);
328   }
329   aconf->port = tmpport;
330   return 0;
331 }
332
333   
334 #if 0
335 /*
336  * XXX - remove when regression testing complete
337  *
338  *  m_connect                           - Added by Jto 11 Feb 1989
339  *
340  *    parv[0] = sender prefix
341  *    parv[1] = servername
342  *    parv[2] = port number
343  *    parv[3] = remote server
344  */
345 int m_connect(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
346 {
347   unsigned short   port;
348   unsigned short   tmpport;
349   struct ConfItem* aconf;
350   struct ConfItem* cconf;
351   struct Client*   acptr;
352
353   if (!IsPrivileged(sptr)) {
354     sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
355     return -1;
356   }
357
358   if (IsLocOp(sptr) && parc > 3)        /* Only allow LocOps to make */
359     return 0;                   /* local CONNECTS --SRB      */
360
361   if (parc > 3 && MyUser(sptr)) {
362     struct Client* acptr2;
363     struct Client* acptr3;
364     if (!(acptr3 = find_match_server(parv[3]))) {
365       sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, parv[0], parv[3]);
366       return 0;
367     }
368
369     /* Look for closest matching server */
370     for (acptr2 = acptr3; acptr2 != &me; acptr2 = acptr2->serv->up)
371       if (!match(parv[3], acptr2->name))
372         acptr3 = acptr2;
373
374     parv[3] = acptr3->name;
375   }
376
377   if (hunt_server(1, cptr, sptr,
378                   "%s%s " TOK_CONNECT " %s %s :%s", 3, parc, parv) != HUNTED_ISME)
379     return 0;
380
381   if (parc < 2 || *parv[1] == '\0') {
382     return need_more_params(sptr, "CONNECT");
383 #if 0
384     return -1;
385 #endif
386   }
387
388   if ((acptr = FindServer(parv[1]))) {
389     if (MyUser(sptr))
390       sendto_one(sptr, ":%s NOTICE %s :Connect: Server %s %s %s.",
391           me.name, parv[0], parv[1], "already exists from", acptr->from->name);
392     else
393       sendto_one(sptr, "%s NOTICE %s%s :Connect: Server %s %s %s.",
394           NumServ(&me), NumNick(sptr), parv[1], "already exists from",
395           acptr->from->name);
396     return 0;
397   }
398
399   for (aconf = GlobalConfList; aconf; aconf = aconf->next) {
400     if (CONF_SERVER == aconf->status && 0 == match(parv[1], aconf->name))
401       break;
402   }
403 #if 0
404   /*
405    * Checked first servernames, then try hostnames.
406    */
407   if (!aconf) {
408     for (aconf = GlobalConfList; aconf; aconf = aconf->next) {
409       if (CONF_SERVER == aconf->status && 0 == match(parv[1], aconf->host))
410         break;
411     }
412   }
413 #endif
414   if (!aconf) {
415     if (MyUser(sptr))
416       sendto_one(sptr, ":%s NOTICE %s :Connect: Host %s not listed in ircd.conf",
417                  me.name, parv[0], parv[1]);
418     else
419       sendto_one(sptr, "%s NOTICE %s%s :Connect: Host %s not listed in ircd.conf",
420                  NumServ(&me), NumNick(sptr), parv[1]);
421     return 0;
422   }
423   /*
424    *  Get port number from user, if given. If not specified,
425    *  use the default from configuration structure. If missing
426    *  from there, then use the precompiled default.
427    */
428   tmpport = port = aconf->port;
429   if (parc > 2 && !BadPtr(parv[2])) {
430     if ((port = atoi(parv[2])) == 0) {
431       if (MyUser(sptr))
432         sendto_one(sptr, ":%s NOTICE %s :Connect: Invalid port number", me.name, parv[0]);
433       else
434         sendto_one(sptr, "%s NOTICE %s%s :Connect: Invalid port number",
435                    NumServ(&me), NumNick(sptr));
436       return 0;
437     }
438   }
439   else if (port == 0 && (port = PORTNUM) == 0) {
440     if (MyUser(sptr))
441       sendto_one(sptr, ":%s NOTICE %s :Connect: missing port number",
442                  me.name, parv[0]);
443     else
444       sendto_one(sptr, "%s NOTICE %s%s :Connect: missing port number",
445                  NumServ(&me), NumNick(sptr));
446     return 0;
447   }
448
449   /*
450    * Evaluate connection rules...  If no rules found, allow the
451    * connect.   Otherwise stop with the first true rule (ie: rules
452    * are ored together.  Oper connects are effected only by D
453    * lines (CRULEALL) not d lines (CRULEAUTO).
454    */
455   for (cconf = GlobalConfList; cconf; cconf = cconf->next) {
456     if ((CONF_CRULEALL == cconf->status) &&
457         (0 == match(cconf->host, aconf->name))) {
458       if (crule_eval(cconf->passwd)) {
459         if (MyUser(sptr))
460           sendto_one(sptr, ":%s NOTICE %s :Connect: Disallowed by rule: %s",
461                      me.name, parv[0], cconf->name);
462         else
463           sendto_one(sptr, "%s NOTICE %s%s :Connect: Disallowed by rule: %s",
464                      NumServ(&me), NumNick(sptr), cconf->name);
465         return 0;
466       }
467     }
468   }
469
470   /*
471    * Notify all operators about remote connect requests
472    */
473   if (!IsAnOper(cptr)) {
474     sendto_ops_butone(0, &me, ":%s WALLOPS :Remote CONNECT %s %s from %s",
475                       me.name, parv[1], parv[2] ? parv[2] : "",
476                       get_client_name(sptr, HIDE_IP));
477     ircd_log(L_INFO, "CONNECT From %s : %s %d",
478              parv[0], parv[1], parv[2] ? parv[2] : "");
479   }
480   aconf->port = port;
481   if (connect_server(aconf, sptr, 0)) {
482     if (MyUser(sptr))
483       sendto_one(sptr, ":%s NOTICE %s :*** Connecting to %s.",
484                  me.name, parv[0], aconf->name);
485     else
486       sendto_one(sptr, "%s NOTICE %s%s :*** Connecting to %s.",
487                  NumServ(&me), NumNick(sptr), aconf->name);
488   }
489   else {
490     if (MyUser(sptr))
491       sendto_one(sptr, ":%s NOTICE %s :*** Connection to %s failed",
492                  me.name, parv[0], aconf->name);
493     else
494       sendto_one(sptr, "%s NOTICE %s%s :*** Connection to %s failed",
495                  NumServ(&me), NumNick(sptr), aconf->name);
496   }
497   aconf->port = tmpport;
498   return 0;
499 }
500 #endif /* 0 */
501