Author: Run <carlo@alinoe.com>
[ircu2.10.12-pk.git] / ircd / opercmds.c
1 /*
2  * IRC - Internet Relay Chat, ircd/opercmds.c (formerly ircd/s_serv.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
24 #include "sys.h"
25 #include <sys/stat.h>
26 #if HAVE_FCNTL_H
27 #include <fcntl.h>
28 #endif
29 #include <stdlib.h>
30 #if HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33 #ifdef USE_SYSLOG
34 #include <syslog.h>
35 #endif
36 #include "h.h"
37 #include "opercmds.h"
38 #include "struct.h"
39 #include "ircd.h"
40 #include "s_bsd.h"
41 #include "send.h"
42 #include "s_err.h"
43 #include "numeric.h"
44 #include "match.h"
45 #include "s_misc.h"
46 #include "s_conf.h"
47 #include "class.h"
48 #include "s_user.h"
49 #include "common.h"
50 #include "msg.h"
51 #include "sprintf_irc.h"
52 #include "userload.h"
53 #include "parse.h"
54 #include "numnicks.h"
55 #include "crule.h"
56 #include "version.h"
57 #include "support.h"
58 #include "s_serv.h"
59 #include "hash.h"
60
61 RCSTAG_CC("$Id$");
62
63 /*
64  *  m_squit
65  *
66  *    parv[0] = sender prefix
67  *    parv[1] = server name
68  *    parv[2] = timestamp
69  *    parv[parc-1] = comment
70  */
71 int m_squit(aClient *cptr, aClient *sptr, int parc, char *parv[])
72 {
73   Reg1 aConfItem *aconf;
74   char *server;
75   Reg2 aClient *acptr;
76   char *comment = (parc > ((!IsServer(cptr)) ? 2 : 3) &&
77       !BadPtr(parv[parc - 1])) ? parv[parc - 1] : cptr->name;
78
79   if (!IsPrivileged(sptr))
80   {
81     sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
82     return 0;
83   }
84
85   if (parc > (IsServer(cptr) ? 2 : 1))
86   {
87     server = parv[1];
88     /*
89      * To accomodate host masking, a squit for a masked server
90      * name is expanded if the incoming mask is the same as
91      * the server name for that link to the name of link.
92      */
93     if ((*server == '*') && IsServer(cptr) && (aconf = cptr->serv->nline) &&
94         !strCasediff(server, my_name_for_link(me.name, aconf)))
95     {
96       server = cptr->name;
97       acptr = cptr;
98     }
99     else
100     {
101       /*
102        * The following allows wild cards in SQUIT. Only usefull
103        * when the command is issued by an oper.
104        */
105       for (acptr = client; (acptr = next_client(acptr, server));
106           acptr = acptr->next)
107         if (IsServer(acptr) || IsMe(acptr))
108           break;
109
110       if (acptr)
111       {
112         if (IsMe(acptr))
113         {
114           if (IsServer(cptr))
115           {
116             acptr = cptr;
117             server = cptr->sockhost;
118           }
119           else
120             acptr = NULL;
121         }
122         else
123         {
124           /*
125            * Look for a matching server that is closer,
126            * that way we won't accidently squit two close
127            * servers like davis.* and davis-r.* when typing
128            * /SQUIT davis*
129            */
130           aClient *acptr2;
131           for (acptr2 = acptr->serv->up; acptr2 != &me;
132               acptr2 = acptr2->serv->up)
133             if (!match(server, acptr2->name))
134               acptr = acptr2;
135         }
136       }
137     }
138     /* If atoi(parv[2]) == 0 we must indeed squit !
139      * It wil be our neighbour.
140      */
141     if (acptr && IsServer(cptr) &&
142         atoi(parv[2]) && atoi(parv[2]) != acptr->serv->timestamp)
143     {
144       Debug((DEBUG_NOTICE, "Ignoring SQUIT with wrong timestamp"));
145       return 0;
146     }
147   }
148   else
149   {
150     sendto_one(cptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "SQUIT");
151     if (IsServer(cptr))
152     {
153       /*
154        * This is actually protocol error. But, well, closing
155        * the link is very proper answer to that...
156        */
157       server = cptr->sockhost;
158       acptr = cptr;
159     }
160     else
161       return 0;
162   }
163   if (!acptr)
164   {
165     if (IsUser(sptr))
166       sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, parv[0], server);
167     return 0;
168   }
169   if (IsLocOp(sptr) && !MyConnect(acptr))
170   {
171     sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
172     return 0;
173   }
174
175   return exit_client(cptr, acptr, sptr, comment);
176 }
177
178 /*
179  * m_stats/stats_conf
180  *
181  * Report N/C-configuration lines from this server. This could
182  * report other configuration lines too, but converting the
183  * status back to "char" is a bit akward--not worth the code
184  * it needs...
185  *
186  * Note: The info is reported in the order the server uses
187  *       it--not reversed as in ircd.conf!
188  */
189
190 static unsigned int report_array[17][3] = {
191   {CONF_CONNECT_SERVER, RPL_STATSCLINE, 'C'},
192   {CONF_NOCONNECT_SERVER, RPL_STATSNLINE, 'N'},
193   {CONF_CLIENT, RPL_STATSILINE, 'I'},
194   {CONF_KILL, RPL_STATSKLINE, 'K'},
195   {CONF_IPKILL, RPL_STATSKLINE, 'k'},
196   {CONF_LEAF, RPL_STATSLLINE, 'L'},
197   {CONF_OPERATOR, RPL_STATSOLINE, 'O'},
198   {CONF_HUB, RPL_STATSHLINE, 'H'},
199   {CONF_LOCOP, RPL_STATSOLINE, 'o'},
200   {CONF_CRULEALL, RPL_STATSDLINE, 'D'},
201   {CONF_CRULEAUTO, RPL_STATSDLINE, 'd'},
202   {CONF_UWORLD, RPL_STATSULINE, 'U'},
203   {CONF_TLINES, RPL_STATSTLINE, 'T'},
204   {CONF_LISTEN_PORT, RPL_STATSPLINE, 'P'},
205   {0, 0}
206 };
207
208 static void report_configured_links(aClient *sptr, int mask)
209 {
210   static char null[] = "<NULL>";
211   aConfItem *tmp;
212   unsigned int *p;
213   unsigned short int port;
214   char c, *host, *pass, *name;
215
216   for (tmp = conf; tmp; tmp = tmp->next)
217     if ((tmp->status & mask))
218     {
219       for (p = &report_array[0][0]; *p; p += 3)
220         if (*p == tmp->status)
221           break;
222       if (!*p)
223         continue;
224       c = (char)*(p + 2);
225       host = BadPtr(tmp->host) ? null : tmp->host;
226       pass = BadPtr(tmp->passwd) ? null : tmp->passwd;
227       name = BadPtr(tmp->name) ? null : tmp->name;
228       port = tmp->port;
229       /*
230        * On K line the passwd contents can be
231        * displayed on STATS reply.    -Vesa
232        */
233       /* Special-case 'k' or 'K' lines as appropriate... -Kev */
234       if ((tmp->status & CONF_KLINE))
235         sendto_one(sptr, rpl_str(p[1]), me.name,
236             sptr->name, c, host, pass, name, port, get_conf_class(tmp));
237       /* connect rules are classless */
238       else if ((tmp->status & CONF_CRULE))
239         sendto_one(sptr, rpl_str(p[1]), me.name, sptr->name, c, host, name);
240       else if ((tmp->status & CONF_TLINES))
241         sendto_one(sptr, rpl_str(p[1]), me.name, sptr->name, c, host, pass);
242       else if ((tmp->status & CONF_LISTEN_PORT))
243         sendto_one(sptr, rpl_str(p[1]), me.name, sptr->name, c, port,
244             tmp->clients, tmp->status);
245       else if ((tmp->status & CONF_UWORLD))
246         sendto_one(sptr, rpl_str(p[1]),
247             me.name, sptr->name, c, host, pass, name, port,
248             get_conf_class(tmp));
249       else
250         sendto_one(sptr, rpl_str(p[1]), me.name, sptr->name, c, host, name,
251             port, get_conf_class(tmp));
252     }
253   return;
254 }
255
256 /*
257  * m_stats
258  *
259  *    parv[0] = sender prefix
260  *    parv[1] = statistics selector (defaults to Message frequency)
261  *    parv[2] = target server (current server defaulted, if omitted)
262  * And 'stats l' and 'stats' L:
263  *    parv[3] = server mask ("*" defaulted, if omitted)
264  * Or for stats p,P:
265  *    parv[3] = port mask (returns p-lines when its port is matched by this)
266  * Or for stats k,K,i and I:
267  *    parv[3] = [user@]host.name  (returns which K/I-lines match this)
268  *           or [user@]host.mask  (returns which K/I-lines are mmatched by this)
269  *              (defaults to old reply if ommitted, when local or Oper)
270  *              A remote mask (something containing wildcards) is only
271  *              allowed for IRC Operators.
272  * Or for stats M:
273  *    parv[3] = time param
274  *    parv[4] = time param 
275  *    (see report_memleak_stats() in runmalloc.c for details)
276  *
277  * This function is getting really ugly. -Ghostwolf
278  */
279 int m_stats(aClient *cptr, aClient *sptr, int parc, char *parv[])
280 {
281   static char Sformat[] = ":%s %d %s Connection SendQ SendM SendKBytes "
282       "RcveM RcveKBytes :Open since";
283   static char Lformat[] = ":%s %d %s %s %u %u %u %u %u :" TIME_T_FMT;
284   aMessage *mptr;
285   aClient *acptr;
286   aGline *agline, *a2gline;
287   aConfItem *aconf;
288   char stat = parc > 1 ? parv[1][0] : '\0';
289   Reg1 int i;
290
291 /* m_stats is so obnoxiously full of special cases that the different
292  * hunt_server() possiblites were becoming very messy. It now uses a
293  * switch() so as to be easier to read and update as params change. 
294  * -Ghostwolf 
295  */
296   switch (stat)
297   {
298       /* open to all, standard # of params */
299     case 'U':
300     case 'u':
301     {
302       if (hunt_server(0, cptr, sptr, ":%s STATS %s :%s", 2, parc, parv)
303           != HUNTED_ISME)
304         return 0;
305       break;
306     }
307
308       /* open to all, varying # of params */
309     case 'k':
310     case 'K':
311     case 'i':
312     case 'I':
313     case 'p':
314     case 'P':
315     {
316       if (parc > 3)
317       {
318         if (hunt_server(0, cptr, sptr, ":%s STATS %s %s :%s", 2, parc, parv)
319             != HUNTED_ISME)
320           return 0;
321       }
322       else
323       {
324         if (hunt_server(0, cptr, sptr, ":%s STATS %s :%s", 2, parc, parv)
325             != HUNTED_ISME)
326           return 0;
327       }
328       break;
329     }
330
331       /* oper only, varying # of params */
332     case 'l':
333     case 'L':
334     case 'M':
335     {
336       if (parc == 4)
337       {
338         if (hunt_server(1, cptr, sptr, ":%s STATS %s %s :%s", 2, parc, parv)
339             != HUNTED_ISME)
340           return 0;
341       }
342       else if (parc > 4)
343       {
344         if (hunt_server(1, cptr, sptr, ":%s STATS %s %s %s :%s", 2, parc,
345             parv) != HUNTED_ISME)
346           return 0;
347       }
348       else if (hunt_server(1, cptr, sptr, ":%s STATS %s :%s", 2, parc, parv)
349           != HUNTED_ISME)
350         return 0;
351       break;
352     }
353
354       /* oper only, standard # of params */
355     default:
356     {
357       if (hunt_server(1, cptr, sptr, ":%s STATS %s :%s", 2, parc, parv)
358           != HUNTED_ISME)
359         return 0;
360       break;
361     }
362   }
363
364   switch (stat)
365   {
366     case 'L':
367     case 'l':
368     {
369       int doall = 0, wilds = 0;
370       char *name = "*";
371       if (parc > 3 && *parv[3])
372       {
373         char *p;
374         name = parv[3];
375         wilds = (*name == '*' || *name == '?');
376         for (p = name + 1; *p; ++p)
377           if ((*p == '*' || *p == '?') && p[-1] != '\\')
378           {
379             wilds = 1;
380             break;
381           }
382       }
383       else
384         doall = 1;
385       /*
386        * Send info about connections which match, or all if the
387        * mask matches me.name.  Only restrictions are on those who
388        * are invisible not being visible to 'foreigners' who use
389        * a wild card based search to list it.
390        */
391       sendto_one(sptr, Sformat, me.name, RPL_STATSLINKINFO, parv[0]);
392       for (i = 0; i <= highest_fd; i++)
393       {
394         if (!(acptr = loc_clients[i]))
395           continue;
396         /* Don't return clients when this is a request for `all' */
397         if (doall && IsUser(acptr))
398           continue;
399         /* Don't show invisible people to unauthorized people when using
400          * wildcards  -- Is this still needed now /stats is oper only ? */
401         if (IsInvisible(acptr) && (doall || wilds) &&
402             !(MyConnect(sptr) && IsOper(sptr)) &&
403             !IsAnOper(acptr) && (acptr != sptr))
404           continue;
405         /* Only show the ones that match the given mask - if any */
406         if (!doall && wilds && match(name, acptr->name))
407           continue;
408         /* Skip all that do not match the specific query */
409         if (!(doall || wilds) && strCasediff(name, acptr->name))
410           continue;
411         sendto_one(sptr, Lformat, me.name, RPL_STATSLINKINFO, parv[0],
412             (isUpper(stat)) ?
413             get_client_name(acptr, TRUE) : get_client_name(acptr, FALSE),
414             (int)DBufLength(&acptr->sendQ), (int)acptr->sendM,
415             (int)acptr->sendK, (int)acptr->receiveM, (int)acptr->receiveK,
416             time(NULL) - acptr->firsttime);
417       }
418       break;
419     }
420     case 'C':
421     case 'c':
422       report_configured_links(sptr,
423           CONF_CONNECT_SERVER | CONF_NOCONNECT_SERVER);
424       break;
425     case 'G':
426     case 'g':
427       /* send glines */
428       for (agline = gline, a2gline = NULL; agline; agline = agline->next)
429       {
430         if (agline->expire <= TStime())
431         {                       /* handle expired glines */
432           free_gline(agline, a2gline);
433           agline = a2gline ? a2gline : gline;   /* make sure to splice
434                                                    list together */
435           if (!agline)
436             break;              /* last gline; break out of loop */
437           continue;             /* continue! */
438         }
439         sendto_one(sptr, rpl_str(RPL_STATSGLINE), me.name,
440             sptr->name, 'G', agline->name, agline->host,
441             agline->expire, agline->reason);
442         a2gline = agline;
443       }
444       break;
445     case 'H':
446     case 'h':
447       report_configured_links(sptr, CONF_HUB | CONF_LEAF);
448       break;
449     case 'I':
450     case 'i':
451     case 'K':
452     case 'k':                   /* display CONF_IPKILL as well
453                                    as CONF_KILL -Kev */
454     {
455       int wilds, count;
456       char *user, *host, *p;
457       int conf_status = (stat == 'k' || stat == 'K') ? CONF_KLINE : CONF_CLIENT;
458       if ((MyUser(sptr) || IsOper(sptr)) && parc < 4)
459       {
460         report_configured_links(sptr, conf_status);
461         break;
462       }
463       if (parc < 4 || *parv[3] == '\0')
464       {
465         sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0],
466             (conf_status & CONF_KLINE) ? "STATS K" : "STATS I");
467         return 0;
468       }
469       wilds = 0;
470       for (p = parv[3]; *p; p++)
471       {
472         if (*p == '\\')
473         {
474           if (!*++p)
475             break;
476           continue;
477         }
478         if (*p == '?' || *p == '*')
479         {
480           wilds = 1;
481           break;
482         }
483       }
484       if (!(MyConnect(sptr) || IsOper(sptr)))
485       {
486         wilds = 0;
487         count = 3;
488       }
489       else
490         count = 1000;
491
492       if (conf_status == CONF_CLIENT)
493       {
494         user = NULL;            /* Not used, but to avoid compiler warning. */
495
496         host = parv[3];
497       }
498       else
499       {
500         if ((host = strchr(parv[3], '@')))
501         {
502           user = parv[3];
503           *host++ = 0;;
504         }
505         else
506         {
507           user = NULL;
508           host = parv[3];
509         }
510       }
511       for (aconf = conf; aconf; aconf = aconf->next)
512       {
513         if ((aconf->status & conf_status))
514         {
515           if (conf_status == CONF_KLINE)
516           {
517             if ((!wilds && ((user || aconf->host[1]) &&
518                 !match(aconf->host, host) &&
519                 (!user || !match(aconf->name, user)))) ||
520                 (wilds && !mmatch(host, aconf->host) &&
521                 (!user || !mmatch(user, aconf->name))))
522             {
523               sendto_one(sptr, rpl_str(RPL_STATSKLINE), me.name,
524                   sptr->name, 'K', aconf->host, aconf->passwd, aconf->name,
525                   aconf->port, get_conf_class(aconf));
526               if (--count == 0)
527                 break;
528             }
529           }
530           else if (conf_status == CONF_CLIENT)
531           {
532             if ((!wilds && (!match(aconf->host, host) ||
533                 !match(aconf->name, host))) ||
534                 (wilds && (!mmatch(host, aconf->host) ||
535                 !mmatch(host, aconf->name))))
536             {
537               sendto_one(sptr, rpl_str(RPL_STATSILINE), me.name,
538                   sptr->name, 'I', aconf->host, aconf->name,
539                   aconf->port, get_conf_class(aconf));
540               if (--count == 0)
541                 break;
542             }
543           }
544         }
545       }
546       break;
547     }
548     case 'M':
549 #ifdef MEMSIZESTATS
550       sendto_one(sptr, rpl_str(RPL_STATMEMTOT),
551           me.name, parv[0], get_mem_size(), get_alloc_cnt());
552 #endif
553 #ifdef MEMLEAKSTATS
554       report_memleak_stats(sptr, parc, parv);
555 #endif
556 #if !defined(MEMSIZESTATS) && !defined(MEMLEAKSTATS)
557       sendto_one(sptr, ":%s NOTICE %s :stats M : Memory allocation monitoring "
558           "is not enabled on this server", me.name, parv[0]);
559 #endif
560       break;
561     case 'm':
562       for (mptr = msgtab; mptr->cmd; mptr++)
563         if (mptr->count)
564           sendto_one(sptr, rpl_str(RPL_STATSCOMMANDS),
565               me.name, parv[0], mptr->cmd, mptr->count, mptr->bytes);
566       break;
567     case 'o':
568     case 'O':
569       report_configured_links(sptr, CONF_OPS);
570       break;
571     case 'p':
572     case 'P':
573     {
574       int count = 100;
575       char port[6];
576       if ((MyUser(sptr) || IsOper(sptr)) && parc < 4)
577       {
578         report_configured_links(sptr, CONF_LISTEN_PORT);
579         break;
580       }
581       if (!(MyConnect(sptr) || IsOper(sptr)))
582         count = 3;
583       for (aconf = conf; aconf; aconf = aconf->next)
584         if (aconf->status == CONF_LISTEN_PORT)
585         {
586           if (parc >= 4 && *parv[3] != '\0')
587           {
588             sprintf_irc(port, "%u", aconf->port);
589             if (match(parv[3], port))
590               continue;
591           }
592           sendto_one(sptr, rpl_str(RPL_STATSPLINE), me.name, sptr->name, 'P',
593               aconf->port, aconf->clients, aconf->status);
594           if (--count == 0)
595             break;
596         }
597       break;
598     }
599     case 'R':
600     case 'r':
601 #ifdef DEBUGMODE
602       send_usage(sptr, parv[0]);
603 #endif
604       break;
605     case 'D':
606       report_configured_links(sptr, CONF_CRULEALL);
607       break;
608     case 'd':
609       report_configured_links(sptr, CONF_CRULE);
610       break;
611     case 't':
612       tstats(sptr, parv[0]);
613       break;
614     case 'T':
615       report_configured_links(sptr, CONF_TLINES);
616       break;
617     case 'U':
618       report_configured_links(sptr, CONF_UWORLD);
619       break;
620     case 'u':
621     {
622       register time_t nowr;
623
624       nowr = now - me.since;
625       sendto_one(sptr, rpl_str(RPL_STATSUPTIME), me.name, parv[0],
626           nowr / 86400, (nowr / 3600) % 24, (nowr / 60) % 60, nowr % 60);
627       sendto_one(sptr, rpl_str(RPL_STATSCONN), me.name, parv[0],
628           max_connection_count, max_client_count);
629       break;
630     }
631     case 'W':
632     case 'w':
633       calc_load(sptr);
634       break;
635     case 'X':
636     case 'x':
637 #ifdef  DEBUGMODE
638       send_listinfo(sptr, parv[0]);
639 #endif
640       break;
641     case 'Y':
642     case 'y':
643       report_classes(sptr);
644       break;
645     case 'Z':
646     case 'z':
647       count_memory(sptr, parv[0]);
648       break;
649     default:
650       stat = '*';
651       break;
652   }
653   sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], stat);
654   return 0;
655 }
656
657 /*
658  *  m_connect                           - Added by Jto 11 Feb 1989
659  *
660  *    parv[0] = sender prefix
661  *    parv[1] = servername
662  *    parv[2] = [IP-number:]port number
663  *    parv[3] = remote server
664  */
665 int m_connect(aClient *cptr, aClient *sptr, int parc, char *parv[])
666 {
667   int retval;
668   unsigned short int port, tmpport;
669   aConfItem *aconf, *cconf;
670   aClient *acptr;
671   char *p;
672
673   if (!IsPrivileged(sptr))
674   {
675     sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
676     return -1;
677   }
678
679   if (IsLocOp(sptr) && parc > 3)        /* Only allow LocOps to make */
680     return 0;                   /* local CONNECTS --SRB      */
681
682   if (parc > 3 && MyUser(sptr))
683   {
684     aClient *acptr2, *acptr3;
685     if (!(acptr3 = find_match_server(parv[3])))
686     {
687       sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, parv[0], parv[3]);
688       return 0;
689     }
690
691     /* Look for closest matching server */
692     for (acptr2 = acptr3; acptr2 != &me; acptr2 = acptr2->serv->up)
693       if (!match(parv[3], acptr2->name))
694         acptr3 = acptr2;
695
696     parv[3] = acptr3->name;
697   }
698
699   if (hunt_server(1, cptr, sptr, ":%s CONNECT %s %s :%s", 3, parc, parv) !=
700       HUNTED_ISME)
701     return 0;
702
703   if (parc < 2 || *parv[1] == '\0')
704   {
705     sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "CONNECT");
706     return -1;
707   }
708
709   if ((acptr = FindServer(parv[1])))
710   {
711     if (MyUser(sptr) || Protocol(cptr) < 10)
712       sendto_one(sptr, ":%s NOTICE %s :Connect: Server %s %s %s.",
713           me.name, parv[0], parv[1], "already exists from", acptr->from->name);
714     else
715       sendto_one(sptr, "%s NOTICE %s%s :Connect: Server %s %s %s.",
716           NumServ(&me), NumNick(sptr), parv[1], "already exists from",
717           acptr->from->name);
718     return 0;
719   }
720
721   if (parc > 2 && !BadPtr(parv[2]))
722     p = strchr(parv[2], ':');
723   else
724     p = 0;
725   if (p)
726     *p = 0;
727   for (aconf = conf; aconf; aconf = aconf->next)
728     if (aconf->status == CONF_CONNECT_SERVER &&
729         match(parv[1], aconf->name) == 0 &&
730         (!p || match(parv[2], aconf->host) == 0 ||
731         match(parv[2], strchr(aconf->host, '@') + 1) == 0))
732       break;
733   /* Checked first servernames, then try hostnames. */
734   if (!aconf)
735     for (aconf = conf; aconf; aconf = aconf->next)
736       if (aconf->status == CONF_CONNECT_SERVER &&
737           (match(parv[1], aconf->host) == 0 ||
738           match(parv[1], strchr(aconf->host, '@') + 1) == 0))
739         break;
740   if (p)
741     *p = ':';
742
743   if (!aconf)
744   {
745     if (MyUser(sptr) || Protocol(cptr) < 10)
746       sendto_one(sptr,
747           ":%s NOTICE %s :Connect: Host %s not listed in ircd.conf",
748           me.name, parv[0], parv[1]);
749     else
750       sendto_one(sptr,
751           "%s NOTICE %s%s :Connect: Host %s not listed in ircd.conf",
752           NumServ(&me), NumNick(sptr), parv[1]);
753     return 0;
754   }
755   /*
756    *  Get port number from user, if given. If not specified,
757    *  use the default from configuration structure. If missing
758    *  from there, then use the precompiled default.
759    */
760   tmpport = port = aconf->port;
761   if (parc > 2 && !BadPtr(parv[2]))
762   {
763     p = strchr(parv[2], ':');
764     if (!p)
765       p = parv[2];
766     else
767       p = p + 1;
768     if ((port = atoi(p)) == 0)
769     {
770       if (MyUser(sptr) || Protocol(cptr) < 10)
771         sendto_one(sptr,
772             ":%s NOTICE %s :Connect: Invalid port number", me.name, parv[0]);
773       else
774         sendto_one(sptr, "%s NOTICE %s%s :Connect: Invalid port number",
775             NumServ(&me), NumNick(sptr));
776       return 0;
777     }
778   }
779   else if (port == 0 && (port = PORTNUM) == 0)
780   {
781     if (MyUser(sptr) || Protocol(cptr) < 10)
782       sendto_one(sptr, ":%s NOTICE %s :Connect: missing port number",
783           me.name, parv[0]);
784     else
785       sendto_one(sptr, "%s NOTICE %s%s :Connect: missing port number",
786           NumServ(&me), NumNick(sptr));
787     return 0;
788   }
789
790   /*
791    * Evaluate connection rules...  If no rules found, allow the
792    * connect.   Otherwise stop with the first true rule (ie: rules
793    * are ored together.  Oper connects are effected only by D
794    * lines (CRULEALL) not d lines (CRULEAUTO).
795    */
796   for (cconf = conf; cconf; cconf = cconf->next)
797     if ((cconf->status == CONF_CRULEALL) &&
798         (match(cconf->host, aconf->name) == 0))
799       if (crule_eval(cconf->passwd))
800       {
801         if (MyUser(sptr) || Protocol(cptr) < 10)
802           sendto_one(sptr, ":%s NOTICE %s :Connect: Disallowed by rule: %s",
803               me.name, parv[0], cconf->name);
804         else
805           sendto_one(sptr, "%s NOTICE %s%s :Connect: Disallowed by rule: %s",
806               NumServ(&me), NumNick(sptr), cconf->name);
807         return 0;
808       }
809
810   /*
811    * Notify all operators about remote connect requests
812    */
813   if (!IsAnOper(cptr))
814   {
815     sendto_ops_butone(NULL, &me, ":%s WALLOPS :Remote CONNECT %s %s from %s",
816         me.name, parv[1], parv[2] ? parv[2] : "", get_client_name(sptr, FALSE));
817 #if defined(USE_SYSLOG) && defined(SYSLOG_CONNECT)
818     syslog(LOG_DEBUG,
819         "CONNECT From %s : %s %d", parv[0], parv[1], parv[2] ? parv[2] : "");
820 #endif
821   }
822   aconf->port = port;
823   switch (retval = connect_server(aconf, sptr, NULL))
824   {
825     case 0:
826       if (MyUser(sptr) || Protocol(cptr) < 10)
827         sendto_one(sptr,
828             ":%s NOTICE %s :*** Connecting to %s[%s].",
829             me.name, parv[0], aconf->host, aconf->name);
830       else
831         sendto_one(sptr,
832             "%s NOTICE %s%s :*** Connecting to %s[%s].",
833             NumServ(&me), NumNick(sptr), aconf->host, aconf->name);
834       break;
835     case -1:
836       /* Comments already sent */
837       break;
838     case -2:
839       if (MyUser(sptr) || Protocol(cptr) < 10)
840         sendto_one(sptr, ":%s NOTICE %s :*** Host %s is unknown.",
841             me.name, parv[0], aconf->host);
842       else
843         sendto_one(sptr, "%s NOTICE %s%s :*** Host %s is unknown.",
844             NumServ(&me), NumNick(sptr), aconf->host);
845       break;
846     default:
847       if (MyUser(sptr) || Protocol(cptr) < 10)
848         sendto_one(sptr,
849             ":%s NOTICE %s :*** Connection to %s failed: %s",
850             me.name, parv[0], aconf->host, strerror(retval));
851       else
852         sendto_one(sptr,
853             "%s NOTICE %s%s :*** Connection to %s failed: %s",
854             NumServ(&me), NumNick(sptr), aconf->host, strerror(retval));
855   }
856   aconf->port = tmpport;
857   return 0;
858 }
859
860 /*
861  * m_wallops
862  *
863  * Writes to all +w users currently online
864  *
865  * parv[0] = sender prefix
866  * parv[1] = message text
867  */
868 int m_wallops(aClient *cptr, aClient *sptr, int parc, char *parv[])
869 {
870   char *message;
871
872   message = parc > 1 ? parv[1] : NULL;
873
874   if (BadPtr(message))
875   {
876     sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "WALLOPS");
877     return 0;
878   }
879
880   if (!IsServer(sptr) && MyConnect(sptr) && !IsAnOper(sptr))
881   {
882     sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
883     return 0;
884   }
885   sendto_ops_butone(IsServer(cptr) ? cptr : NULL, sptr,
886       ":%s WALLOPS :%s", parv[0], message);
887   return 0;
888 }
889
890 /*
891  * m_time
892  *
893  * parv[0] = sender prefix
894  * parv[1] = servername
895  */
896 int m_time(aClient *cptr, aClient *sptr, int parc, char *parv[])
897 {
898   if (hunt_server(0, cptr, sptr, ":%s TIME :%s", 1, parc, parv) == HUNTED_ISME)
899     sendto_one(sptr, rpl_str(RPL_TIME), me.name,
900         parv[0], me.name, TStime(), TSoffset, date((long)0));
901   return 0;
902 }
903
904 /*
905  * m_settime
906  *
907  * parv[0] = sender prefix
908  * parv[1] = new time
909  * parv[2] = servername (Only used when sptr is an Oper).
910  */
911 int m_settime(aClient *cptr, aClient *sptr, int parc, char *parv[])
912 {
913   time_t t;
914   long int dt;
915   static char tbuf[11];
916   Dlink *lp;
917
918   if (!IsPrivileged(sptr))
919     return 0;
920
921   if (parc < 2)
922   {
923     sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "SETTIME");
924     return 0;
925   }
926
927   if (parc == 2 && MyUser(sptr))
928     parv[parc++] = me.name;
929
930   t = atoi(parv[1]);
931   dt = TStime() - t;
932
933   if (t < 779557906 || dt < -9000000)
934   {
935     sendto_one(sptr, ":%s NOTICE %s :SETTIME: Bad value", me.name, parv[0]);
936     return 0;
937   }
938
939   if (IsServer(sptr))           /* send to unlagged servers */
940   {
941 #ifdef RELIABLE_CLOCK
942     sprintf_irc(tbuf, TIME_T_FMT, TStime());
943     parv[1] = tbuf;
944 #endif
945     for (lp = me.serv->down; lp; lp = lp->next)
946       if (cptr != lp->value.cptr && DBufLength(&lp->value.cptr->sendQ) < 8000)
947         sendto_one(lp->value.cptr, ":%s SETTIME %s", parv[0], parv[1]);
948   }
949   else
950   {
951     sprintf_irc(tbuf, TIME_T_FMT, TStime());
952     parv[1] = tbuf;
953     if (hunt_server(1, cptr, sptr, ":%s SETTIME %s %s", 2, parc, parv) !=
954         HUNTED_ISME)
955       return 0;
956   }
957
958 #ifdef RELIABLE_CLOCK
959   if ((dt > 600) || (dt < -600))
960     sendto_serv_butone((aClient *)NULL,
961         ":%s WALLOPS :Bad SETTIME from %s: " TIME_T_FMT, me.name, sptr->name,
962         t);
963   if (IsUser(sptr))
964   {
965     if (MyUser(sptr) || Protocol(cptr) < 10)
966       sendto_one(sptr, ":%s NOTICE %s :clock is not set %ld seconds %s : "
967           "RELIABLE_CLOCK is defined", me.name, parv[0],
968           (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards");
969     else
970       sendto_one(sptr, "%s NOTICE %s%s :clock is not set %ld seconds %s : "
971           "RELIABLE_CLOCK is defined", NumServ(&me), NumNick(sptr),
972           (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards");
973   }
974 #else
975   sendto_ops("SETTIME from %s, clock is set %ld seconds %s",
976       get_client_name(sptr, FALSE), (dt < 0) ? -dt : dt,
977       (dt < 0) ? "forwards" : "backwards");
978   TSoffset -= dt;
979   if (IsUser(sptr))
980   {
981     if (MyUser(sptr) || Protocol(cptr) < 10)
982       sendto_one(sptr, ":%s NOTICE %s :clock is set %ld seconds %s", me.name,
983           parv[0], (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards");
984     else
985       sendto_one(sptr, "%s NOTICE %s%s :clock is set %ld seconds %s",
986           NumServ(&me), NumNick(sptr),
987           (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards");
988   }
989 #endif
990   return 0;
991 }
992
993 static char *militime(char *sec, char *usec)
994 {
995   struct timeval tv;
996   static char timebuf[18];
997
998   gettimeofday(&tv, NULL);
999   if (sec && usec)
1000 #if defined(__sun__) || defined(__bsdi__) || (__GLIBC__ >= 2) || defined(__NetBSD__)
1001     sprintf(timebuf, "%ld",
1002         (tv.tv_sec - atoi(sec)) * 1000 + (tv.tv_usec - atoi(usec)) / 1000);
1003 #else
1004     sprintf_irc(timebuf, "%d",
1005         (tv.tv_sec - atoi(sec)) * 1000 + (tv.tv_usec - atoi(usec)) / 1000);
1006 #endif
1007   else
1008 #if defined(__sun__) || defined(__bsdi__) || (__GLIBC__ >= 2) || defined(__NetBSD__)
1009     sprintf(timebuf, "%ld %ld", tv.tv_sec, tv.tv_usec);
1010 #else
1011     sprintf_irc(timebuf, "%d %d", tv.tv_sec, tv.tv_usec);
1012 #endif
1013   return timebuf;
1014 }
1015
1016 /*
1017  * m_rping  -- by Run
1018  *
1019  *    parv[0] = sender (sptr->name thus)
1020  * if sender is a person: (traveling towards start server)
1021  *    parv[1] = pinged server[mask]
1022  *    parv[2] = start server (current target)
1023  *    parv[3] = optional remark
1024  * if sender is a server: (traveling towards pinged server)
1025  *    parv[1] = pinged server (current target)
1026  *    parv[2] = original sender (person)
1027  *    parv[3] = start time in s
1028  *    parv[4] = start time in us
1029  *    parv[5] = the optional remark
1030  */
1031 int m_rping(aClient *cptr, aClient *sptr, int parc, char *parv[])
1032 {
1033   aClient *acptr;
1034
1035   if (!IsPrivileged(sptr))
1036     return 0;
1037
1038   if (parc < (IsAnOper(sptr) ? (MyConnect(sptr) ? 2 : 3) : 6))
1039   {
1040     sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "RPING");
1041     return 0;
1042   }
1043   if (MyUser(sptr))
1044   {
1045     if (parc == 2)
1046       parv[parc++] = me.name;
1047     else if (!(acptr = find_match_server(parv[2])))
1048     {
1049       parv[3] = parv[2];
1050       parv[2] = me.name;
1051       parc++;
1052     }
1053     else
1054       parv[2] = acptr->name;
1055     if (parc == 3)
1056       parv[parc++] = "<No client start time>";
1057   }
1058
1059   if (IsAnOper(sptr))
1060   {
1061     if (hunt_server(1, cptr, sptr, ":%s RPING %s %s :%s", 2, parc, parv) !=
1062         HUNTED_ISME)
1063       return 0;
1064     if (!(acptr = find_match_server(parv[1])) || !IsServer(acptr))
1065     {
1066       sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, parv[0], parv[1]);
1067       return 0;
1068     }
1069     if (Protocol(acptr->from) < 10)
1070       sendto_one(acptr, ":%s RPING %s %s %s :%s",
1071           me.name, acptr->name, sptr->name, militime(NULL, NULL), parv[3]);
1072     else
1073       sendto_one(acptr, ":%s RPING %s %s %s :%s",
1074           me.name, NumServ(acptr), sptr->name, militime(NULL, NULL), parv[3]);
1075   }
1076   else
1077   {
1078     if (hunt_server(1, cptr, sptr, ":%s RPING %s %s %s %s :%s", 1, parc, parv)
1079         != HUNTED_ISME)
1080       return 0;
1081     sendto_one(cptr, ":%s RPONG %s %s %s %s :%s", me.name, parv[0],
1082         parv[2], parv[3], parv[4], parv[5]);
1083   }
1084   return 0;
1085 }
1086
1087 /*
1088  * m_rpong  -- by Run too :)
1089  *
1090  * parv[0] = sender prefix
1091  * parv[1] = from pinged server: start server; from start server: sender
1092  * parv[2] = from pinged server: sender; from start server: pinged server
1093  * parv[3] = pingtime in ms
1094  * parv[4] = client info (for instance start time)
1095  */
1096 int m_rpong(aClient *UNUSED(cptr), aClient *sptr, int parc, char *parv[])
1097 {
1098   aClient *acptr;
1099
1100   if (!IsServer(sptr))
1101     return 0;
1102
1103   if (parc < 5)
1104   {
1105     sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "RPING");
1106     return 0;
1107   }
1108
1109   if (!(acptr = FindClient(parv[1])))
1110     return 0;
1111
1112   if (!IsMe(acptr))
1113   {
1114     if (IsServer(acptr) && parc > 5)
1115     {
1116       sendto_one(acptr, ":%s RPONG %s %s %s %s :%s",
1117           parv[0], parv[1], parv[2], parv[3], parv[4], parv[5]);
1118       return 0;
1119     }
1120   }
1121   else
1122   {
1123     parv[1] = parv[2];
1124     parv[2] = sptr->name;
1125     parv[0] = me.name;
1126     parv[3] = militime(parv[3], parv[4]);
1127     parv[4] = parv[5];
1128     if (!(acptr = FindUser(parv[1])))
1129       return 0;                 /* No bouncing between servers ! */
1130   }
1131
1132   sendto_one(acptr, ":%s RPONG %s %s %s :%s",
1133       parv[0], parv[1], parv[2], parv[3], parv[4]);
1134   return 0;
1135 }
1136
1137 #if defined(OPER_REHASH) || defined(LOCOP_REHASH)
1138 /*
1139  * m_rehash
1140  */
1141 int m_rehash(aClient *cptr, aClient *sptr, int parc, char *parv[])
1142 {
1143 #ifndef LOCOP_REHASH
1144   if (!MyUser(sptr) || !IsOper(sptr))
1145 #else
1146 #ifdef  OPER_REHASH
1147   if (!MyUser(sptr) || !IsAnOper(sptr))
1148 #else
1149   if (!MyUser(sptr) || !IsLocOp(sptr))
1150 #endif
1151 #endif
1152   {
1153     sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
1154     return 0;
1155   }
1156   sendto_one(sptr, rpl_str(RPL_REHASHING), me.name, parv[0], configfile);
1157   sendto_ops("%s is rehashing Server config file", parv[0]);
1158 #ifdef USE_SYSLOG
1159   syslog(LOG_INFO, "REHASH From %s\n", get_client_name(sptr, FALSE));
1160 #endif
1161   return rehash(cptr, (parc > 1) ? ((*parv[1] == 'q') ? 2 : 0) : 0);
1162 }
1163 #endif
1164
1165 #if defined(OPER_RESTART) || defined(LOCOP_RESTART)
1166 /*
1167  * m_restart
1168  */
1169 int m_restart(aClient *UNUSED(cptr), aClient *sptr, int UNUSED(parc),
1170     char *parv[])
1171 {
1172 #ifndef LOCOP_RESTART
1173   if (!MyUser(sptr) || !IsOper(sptr))
1174 #else
1175 #ifdef  OPER_RESTART
1176   if (!MyUser(sptr) || !IsAnOper(sptr))
1177 #else
1178   if (!MyUser(sptr) || !IsLocOp(sptr))
1179 #endif
1180 #endif
1181   {
1182     sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
1183     return 0;
1184   }
1185 #ifdef USE_SYSLOG
1186   syslog(LOG_WARNING, "Server RESTART by %s\n", get_client_name(sptr, FALSE));
1187 #endif
1188   server_reboot();
1189   return 0;
1190 }
1191 #endif
1192
1193 /*
1194  * m_trace
1195  *
1196  * parv[0] = sender prefix
1197  * parv[1] = nick or servername
1198  * parv[2] = 'target' servername
1199  */
1200 int m_trace(aClient *cptr, aClient *sptr, int parc, char *parv[])
1201 {
1202   Reg1 int i;
1203   Reg2 aClient *acptr;
1204   aConfClass *cltmp;
1205   char *tname;
1206   int doall, link_s[MAXCONNECTIONS], link_u[MAXCONNECTIONS];
1207   int cnt = 0, wilds, dow;
1208
1209   if (parc < 2 || BadPtr(parv[1]))
1210   {
1211     /* just "TRACE" without parameters. Must be from local client */
1212     parc = 1;
1213     acptr = &me;
1214     tname = me.name;
1215     i = HUNTED_ISME;
1216   }
1217   else if (parc < 3 || BadPtr(parv[2]))
1218   {
1219     /* No target specified. Make one before propagating. */
1220     parc = 2;
1221     tname = parv[1];
1222     if ((acptr = find_match_server(parv[1])) ||
1223         ((acptr = FindClient(parv[1])) && !MyUser(acptr)))
1224     {
1225       if (IsUser(acptr))
1226         parv[2] = acptr->user->server->name;
1227       else
1228         parv[2] = acptr->name;
1229       parc = 3;
1230       parv[3] = NULL;
1231       if ((i = hunt_server(IsServer(acptr), cptr, sptr,
1232           ":%s TRACE %s :%s", 2, parc, parv)) == HUNTED_NOSUCH)
1233         return 0;
1234     }
1235     else
1236       i = HUNTED_ISME;
1237   }
1238   else
1239   {
1240     /* Got "TRACE <tname> :<target>" */
1241     parc = 3;
1242     if (MyUser(sptr) || Protocol(cptr) < 10)
1243       acptr = find_match_server(parv[2]);
1244     else
1245       acptr = FindNServer(parv[2]);
1246     if ((i = hunt_server(0, cptr, sptr,
1247         ":%s TRACE %s :%s", 2, parc, parv)) == HUNTED_NOSUCH)
1248       return 0;
1249     tname = parv[1];
1250   }
1251
1252   if (i == HUNTED_PASS)
1253   {
1254     if (!acptr)
1255       acptr = next_client(client, tname);
1256     else
1257       acptr = acptr->from;
1258     sendto_one(sptr, rpl_str(RPL_TRACELINK), me.name, parv[0],
1259 #ifndef GODMODE
1260         version, debugmode, tname, acptr ? acptr->from->name : "<No_match>");
1261 #else /* GODMODE */
1262         version, debugmode, tname, acptr ? acptr->from->name : "<No_match>",
1263         (acptr && acptr->from->serv) ? acptr->from->serv->timestamp : 0);
1264 #endif /* GODMODE */
1265     return 0;
1266   }
1267
1268   doall = (parv[1] && (parc > 1)) ? !match(tname, me.name) : TRUE;
1269   wilds = !parv[1] || strchr(tname, '*') || strchr(tname, '?');
1270   dow = wilds || doall;
1271
1272   /* Don't give (long) remote listings to lusers */
1273   if (dow && !MyConnect(sptr) && !IsAnOper(sptr))
1274     return 0;
1275
1276   for (i = 0; i < MAXCONNECTIONS; i++)
1277     link_s[i] = 0, link_u[i] = 0;
1278
1279   if (doall)
1280   {
1281     for (acptr = client; acptr; acptr = acptr->next)
1282       if (IsUser(acptr))
1283         link_u[acptr->from->fd]++;
1284       else if (IsServer(acptr))
1285         link_s[acptr->from->fd]++;
1286   }
1287
1288   /* report all direct connections */
1289
1290   for (i = 0; i <= highest_fd; i++)
1291   {
1292     char *name;
1293     unsigned int conClass;
1294
1295     if (!(acptr = loc_clients[i]))      /* Local Connection? */
1296       continue;
1297     if (IsInvisible(acptr) && dow && !(MyConnect(sptr) && IsOper(sptr)) &&
1298         !IsAnOper(acptr) && (acptr != sptr))
1299       continue;
1300     if (!doall && wilds && match(tname, acptr->name))
1301       continue;
1302     if (!dow && strCasediff(tname, acptr->name))
1303       continue;
1304     name = get_client_name(acptr, FALSE);
1305     conClass = get_client_class(acptr);
1306
1307     switch (acptr->status)
1308     {
1309       case STAT_CONNECTING:
1310         sendto_one(sptr, rpl_str(RPL_TRACECONNECTING),
1311             me.name, parv[0], conClass, name);
1312         cnt++;
1313         break;
1314       case STAT_HANDSHAKE:
1315         sendto_one(sptr, rpl_str(RPL_TRACEHANDSHAKE),
1316             me.name, parv[0], conClass, name);
1317         cnt++;
1318         break;
1319       case STAT_ME:
1320         break;
1321       case STAT_UNKNOWN:
1322       case STAT_UNKNOWN_USER:
1323       case STAT_UNKNOWN_SERVER:
1324         sendto_one(sptr, rpl_str(RPL_TRACEUNKNOWN),
1325             me.name, parv[0], conClass, name);
1326         cnt++;
1327         break;
1328       case STAT_USER:
1329         /* Only opers see users if there is a wildcard
1330            but anyone can see all the opers. */
1331         if ((IsAnOper(sptr) && (MyUser(sptr) ||
1332             !(dow && IsInvisible(acptr)))) || !dow || IsAnOper(acptr))
1333         {
1334           if (IsAnOper(acptr))
1335             sendto_one(sptr, rpl_str(RPL_TRACEOPERATOR),
1336                 me.name, parv[0], conClass, name, now - acptr->lasttime);
1337           else
1338             sendto_one(sptr, rpl_str(RPL_TRACEUSER),
1339                 me.name, parv[0], conClass, name, now - acptr->lasttime);
1340           cnt++;
1341         }
1342         break;
1343         /*
1344          * Connection is a server
1345          *
1346          * Serv <class> <nS> <nC> <name> <ConnBy> <last> <age>
1347          *
1348          * class        Class the server is in
1349          * nS           Number of servers reached via this link
1350          * nC           Number of clients reached via this link
1351          * name         Name of the server linked
1352          * ConnBy       Who established this link
1353          * last         Seconds since we got something from this link
1354          * age          Seconds this link has been alive
1355          *
1356          * Additional comments etc......        -Cym-<cym@acrux.net>
1357          */
1358
1359       case STAT_SERVER:
1360         if (acptr->serv->user)
1361           sendto_one(sptr, rpl_str(RPL_TRACESERVER),
1362               me.name, parv[0], conClass, link_s[i],
1363               link_u[i], name, acptr->serv->by,
1364               acptr->serv->user->username,
1365               acptr->serv->user->host,
1366               now - acptr->lasttime, now - acptr->serv->timestamp);
1367         else
1368           sendto_one(sptr, rpl_str(RPL_TRACESERVER),
1369               me.name, parv[0], conClass, link_s[i],
1370               link_u[i], name, *(acptr->serv->by) ?
1371               acptr->serv->by : "*", "*", me.name,
1372               now - acptr->lasttime, now - acptr->serv->timestamp);
1373         cnt++;
1374         break;
1375       case STAT_LOG:
1376         sendto_one(sptr, rpl_str(RPL_TRACELOG),
1377             me.name, parv[0], LOGFILE, acptr->port);
1378         cnt++;
1379         break;
1380       case STAT_PING:
1381         sendto_one(sptr, rpl_str(RPL_TRACEPING), me.name,
1382             parv[0], name, (acptr->acpt) ? acptr->acpt->name : "<null>");
1383         break;
1384       default:                  /* We actually shouldn't come here, -msa */
1385         sendto_one(sptr, rpl_str(RPL_TRACENEWTYPE), me.name, parv[0], name);
1386         cnt++;
1387         break;
1388     }
1389   }
1390   /*
1391    * Add these lines to summarize the above which can get rather long
1392    * and messy when done remotely - Avalon
1393    */
1394   if (!IsAnOper(sptr) || !cnt)
1395   {
1396     if (!cnt)
1397       /* let the user have some idea that its at the end of the trace */
1398       sendto_one(sptr, rpl_str(RPL_TRACESERVER),
1399           me.name, parv[0], 0, link_s[me.fd],
1400           link_u[me.fd], "<No_match>", *(me.serv->by) ?
1401           me.serv->by : "*", "*", me.name, 0, 0);
1402     return 0;
1403   }
1404   for (cltmp = FirstClass(); doall && cltmp; cltmp = NextClass(cltmp))
1405     if (Links(cltmp) > 0)
1406       sendto_one(sptr, rpl_str(RPL_TRACECLASS), me.name,
1407           parv[0], ConClass(cltmp), Links(cltmp));
1408   return 0;
1409 }
1410
1411 /*
1412  *  m_close                              - added by Darren Reed Jul 13 1992.
1413  */
1414 int m_close(aClient *cptr, aClient *sptr, int UNUSED(parc), char *parv[])
1415 {
1416   Reg1 aClient *acptr;
1417   Reg2 int i;
1418   int closed = 0;
1419
1420   if (!MyOper(sptr))
1421   {
1422     sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
1423     return 0;
1424   }
1425
1426   for (i = highest_fd; i; i--)
1427   {
1428     if (!(acptr = loc_clients[i]))
1429       continue;
1430     if (!IsUnknown(acptr) && !IsConnecting(acptr) && !IsHandshake(acptr))
1431       continue;
1432     sendto_one(sptr, rpl_str(RPL_CLOSING), me.name, parv[0],
1433         get_client_name(acptr, TRUE), acptr->status);
1434     exit_client(cptr, acptr, &me, "Oper Closing");
1435     closed++;
1436   }
1437   sendto_one(sptr, rpl_str(RPL_CLOSEEND), me.name, parv[0], closed);
1438   return 0;
1439 }
1440
1441 #if defined(OPER_DIE) || defined(LOCOP_DIE)
1442 /*
1443  * m_die
1444  */
1445 int m_die(aClient *UNUSED(cptr), aClient *sptr, int UNUSED(parc), char *parv[])
1446 {
1447   Reg1 aClient *acptr;
1448   Reg2 int i;
1449
1450 #ifndef LOCOP_DIE
1451   if (!MyUser(sptr) || !IsOper(sptr))
1452 #else
1453 #ifdef  OPER_DIE
1454   if (!MyUser(sptr) || !IsAnOper(sptr))
1455 #else
1456   if (!MyUser(sptr) || !IsLocOp(sptr))
1457 #endif
1458 #endif
1459   {
1460     sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
1461     return 0;
1462   }
1463
1464   for (i = 0; i <= highest_fd; i++)
1465   {
1466     if (!(acptr = loc_clients[i]))
1467       continue;
1468     if (IsUser(acptr))
1469       sendto_one(acptr, ":%s NOTICE %s :Server Terminating. %s",
1470           me.name, acptr->name, get_client_name(sptr, TRUE));
1471     else if (IsServer(acptr))
1472       sendto_one(acptr, ":%s ERROR :Terminated by %s",
1473           me.name, get_client_name(sptr, TRUE));
1474   }
1475 #ifdef __cplusplus
1476   s_die(0);
1477 #else
1478   s_die();
1479 #endif
1480   return 0;
1481 }
1482 #endif
1483
1484 static void add_gline(aClient *sptr, int ip_mask, char *host, char *comment,
1485     char *user, time_t expire, int local)
1486 {
1487   aClient *acptr;
1488   aGline *agline;
1489   int fd,gtype=0;
1490
1491 #ifdef BADCHAN
1492   if(*host=='#' || *host == '&' || *host == '+')
1493     gtype=1;    /* BAD CHANNEL */
1494 #endif
1495   /* Inform ops */
1496   sendto_op_mask(SNO_GLINE,
1497       "%s adding %s%s for %s@%s, expiring at " TIME_T_FMT ": %s", sptr->name,
1498       local ? "local " : "",
1499       gtype ? "BADCHAN":"GLINE", user, host, expire, comment);
1500
1501 #ifdef GPATH
1502   write_log(GPATH,
1503       "# " TIME_T_FMT " %s adding %s %s for %s@%s, expiring at " TIME_T_FMT
1504       ": %s\n", TStime(), sptr->name, local ? "local" : "global",
1505       gtype ? "BADCHAN" : "GLINE", user, host, expire, comment);
1506
1507   /* this can be inserted into the conf */
1508   if(!gtype)
1509     write_log(GPATH, "%c:%s:%s:%s\n", ip_mask ? 'k' : 'K', host, comment, 
1510       user);
1511 #endif /* GPATH */
1512
1513   agline = make_gline(ip_mask, host, comment, user, expire);
1514   if (local)
1515     SetGlineIsLocal(agline);
1516
1517 #ifdef BADCHAN
1518   if(gtype) return;
1519 #endif
1520
1521   for (fd = highest_fd; fd >= 0; --fd)  /* get the users! */
1522     if ((acptr = loc_clients[fd]) && !IsMe(acptr))
1523     {
1524
1525       if (!acptr->user || strlen(acptr->sockhost) > (size_t)HOSTLEN ||
1526           (acptr->user->username ? strlen(acptr->user->username) : 0) >
1527           (size_t)HOSTLEN)
1528         continue;               /* these tests right out of
1529                                    find_kill for safety's sake */
1530
1531       if ((GlineIsIpMask(agline) ?
1532           match(agline->host, inetntoa(acptr->ip)) :
1533           match(agline->host, acptr->sockhost)) == 0 &&
1534           (!acptr->user->username ||
1535           match(agline->name, acptr->user->username) == 0))
1536       {
1537
1538         /* ok, he was the one that got G-lined */
1539         sendto_one(acptr, ":%s %d %s :*** %s.", me.name,
1540             ERR_YOUREBANNEDCREEP, acptr->name, agline->reason);
1541
1542         /* let the ops know about my first kill */
1543         sendto_op_mask(SNO_GLINE, "G-line active for %s",
1544             get_client_name(acptr, FALSE));
1545
1546         /* and get rid of him */
1547         if (sptr != acptr)
1548           exit_client(sptr->from, acptr, &me, "G-lined");
1549       }
1550     }
1551 }
1552
1553 /*
1554  * m_gline
1555  *
1556  * parv[0] = Send prefix
1557  *
1558  * From server:
1559  *
1560  * parv[1] = Target: server numeric
1561  * parv[2] = [+|-]<G-line mask>
1562  * parv[3] = Expiration offset
1563  * parv[4] = Comment
1564  *
1565  * From client:
1566  *
1567  * parv[1] = [+|-]<G-line mask>
1568  * parv[2] = Expiration offset
1569  * parv[3] = Comment
1570  *
1571  */
1572 int m_gline(aClient *cptr, aClient *sptr, int parc, char *parv[])
1573 {
1574   aClient *acptr = NULL;        /* Init. to avoid compiler warning. */
1575
1576   aGline *agline, *a2gline;
1577   char *user, *host;
1578   int active, ip_mask,gtype = 0;
1579   time_t expire = 0;
1580
1581   /* Remove expired G-lines */
1582   for (agline = gline, a2gline = NULL; agline; agline = agline->next)
1583   {
1584     if (agline->expire <= TStime())
1585     {
1586       free_gline(agline, a2gline);
1587       agline = a2gline ? a2gline : gline;
1588       if (!agline)
1589         break;
1590       continue;
1591     }
1592     a2gline = agline;
1593   }
1594
1595 #ifdef BADCHAN
1596   /* Remove expired bad channels */
1597   for (agline = badchan, a2gline = NULL; agline; agline = agline->next)
1598   {
1599     if (agline->expire <= TStime())
1600     {
1601       free_gline(agline, a2gline);
1602       agline = a2gline ? a2gline : badchan;
1603       if (!agline)
1604         break;
1605       continue;
1606     }
1607     a2gline = agline;
1608   }
1609 #endif
1610
1611
1612   if (IsServer(cptr))
1613   {
1614     if (find_conf_host(cptr->confs, sptr->name, CONF_UWORLD))
1615     {
1616       if (parc < 3 || (*parv[2] != '-' && (parc < 5 || *parv[4] == '\0')))
1617       {
1618         sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0],
1619             "GLINE");
1620         return 0;
1621       }
1622
1623       if (*parv[2] == '-')      /* add mode or delete mode? */
1624         active = 0;
1625       else
1626         active = 1;
1627
1628       if (*parv[2] == '+' || *parv[2] == '-')
1629         parv[2]++;              /* step past mode indicator */
1630
1631       /* forward the message appropriately */
1632       if (!strCasediff(parv[1], "*"))   /* global! */
1633         sendto_serv_butone(cptr, active ? ":%s GLINE %s +%s %s :%s" :
1634             ":%s GLINE %s -%s", parv[0], parv[1], parv[2], parv[3], parv[4]);
1635       else if ((
1636 #if 1
1637           /*
1638            * REMOVE THIS after all servers upgraded to 2.10.01 and
1639            * Uworld uses a numeric too
1640            */
1641           (strlen(parv[1]) != 1 && !(acptr = FindClient(parv[1])))) ||
1642           (strlen(parv[1]) == 1 &&
1643 #endif
1644           !(acptr = FindNServer(parv[1]))))
1645         return 0;               /* no such server/user exists; forget it */
1646       else
1647 #if 1
1648 /*
1649  * REMOVE THIS after all servers upgraded to 2.10.01 and
1650  * Uworld uses a numeric too
1651  */
1652       if (IsServer(acptr) || !MyConnect(acptr))
1653 #endif
1654       {
1655         sendto_one(acptr, active ? ":%s GLINE %s +%s %s :%s" :
1656             ":%s GLINE %s -%s", parv[0], parv[1], parv[2], parv[3], parv[4]);   /* single destination */
1657         return 0;               /* only the intended  destination
1658                                    should add this gline */
1659       }
1660
1661       if (!(host = strchr(parv[2], '@')))
1662       {                         /* convert user@host */
1663         user = "*";             /* no @'s; assume username is '*' */
1664         host = parv[2];
1665       }
1666       else
1667       {
1668         user = parv[2];
1669         *(host++) = '\0';       /* break up string at the '@' */
1670       }
1671       ip_mask = check_if_ipmask(host);  /* Store this boolean */
1672 #ifdef BADCHAN
1673       if(*host=='#' || *host == '&' || *host == '+')
1674         gtype=1;                /* BAD CHANNEL GLINE */
1675 #endif
1676
1677       for (agline = (gtype)?badchan:gline, a2gline = NULL; agline; 
1678            agline = agline->next)
1679       {
1680         if (!strCasediff(agline->name, user)
1681             && !strCasediff(agline->host, host))
1682           break;
1683         a2gline = agline;
1684       }
1685
1686       if (!active && agline)
1687       {                         /* removing the gline */
1688         /* notify opers */
1689         sendto_op_mask(SNO_GLINE, "%s removing %s for %s@%s", parv[0],
1690             gtype?"BADCHAN":"GLINE",agline->name, agline->host);
1691
1692 #ifdef GPATH
1693         write_log(GPATH, "# " TIME_T_FMT " %s removing %s for %s@%s\n",
1694             TStime(), parv[0], gtype?"BADCHAN":"GLINE",agline->name, 
1695             agline->host);
1696 #endif /* GPATH */
1697
1698         free_gline(agline, a2gline);    /* remove the gline */
1699       }
1700       else if (active)
1701       {                         /* must be adding a gline */
1702         expire = atoi(parv[3]) + TStime();      /* expire time? */
1703         if (agline && agline->expire < expire)
1704         {                       /* new expire time? */
1705           /* yes, notify the opers */
1706           sendto_op_mask(SNO_GLINE,
1707               "%s resetting expiration time on %s for %s@%s to " TIME_T_FMT,
1708               parv[0], gtype?"BADCHAN":"GLINE",agline->name, agline->host, 
1709               expire);
1710
1711 #ifdef GPATH
1712           write_log(GPATH, "# " TIME_T_FMT " %s resetting expiration time "
1713               "on %s for %s@%s to " TIME_T_FMT "\n",
1714               TStime(), parv[0], gtype?"BADCHAN":"GLINE",
1715                agline->name, agline->host, expire);
1716 #endif /* GPATH */
1717
1718           agline->expire = expire;      /* reset the expire time */
1719         }
1720         else if (!agline)
1721         {                       /* create gline */
1722           for (agline = gtype?badchan:gline; agline; agline = agline->next)
1723             if (!mmatch(agline->name, user) &&
1724                 (ip_mask ? GlineIsIpMask(agline) : !GlineIsIpMask(agline)) &&
1725                 !mmatch(agline->host, host))
1726               return 0;         /* found an existing G-line that matches */
1727
1728           /* add the line: */
1729           add_gline(sptr, ip_mask, host, parv[4], user, expire, 0);
1730         }
1731       }
1732     }
1733   }
1734   else if (parc < 2 || *parv[1] == '\0')
1735   {
1736     /* Not enough args and a user; list glines */
1737     for (agline = gline; agline; agline = agline->next)
1738       sendto_one(cptr, rpl_str(RPL_GLIST), me.name, parv[0],
1739           agline->name, agline->host, agline->expire, agline->reason,
1740           GlineIsActive(agline) ? (GlineIsLocal(agline) ? " (local)" : "") :
1741           " (Inactive)");
1742     sendto_one(cptr, rpl_str(RPL_ENDOFGLIST), me.name, parv[0]);
1743   }
1744   else
1745   {
1746     int priv;
1747
1748 #ifdef LOCOP_LGLINE
1749     priv = IsAnOper(cptr);
1750 #else
1751     priv = IsOper(cptr);
1752 #endif
1753
1754     if (priv)
1755     {                           /* non-oper not permitted to change things */
1756       if (*parv[1] == '-')
1757       {                         /* oper wants to deactivate the gline */
1758         active = 0;
1759         parv[1]++;
1760       }
1761       else if (*parv[1] == '+')
1762       {                         /* oper wants to activate inactive gline */
1763         active = 1;
1764         parv[1]++;
1765       }
1766       else
1767         active = -1;
1768
1769       if (parc > 2)
1770         expire = atoi(parv[2]) + TStime();      /* oper wants to reset
1771                                                    expire TS */
1772     }
1773     else
1774       active = -1;
1775
1776     if (!(host = strchr(parv[1], '@')))
1777     {
1778       user = "*";               /* no @'s; assume username is '*' */
1779       host = parv[1];
1780     }
1781     else
1782     {
1783       user = parv[1];
1784       *(host++) = '\0';         /* break up string at the '@' */
1785     }
1786     ip_mask = check_if_ipmask(host);    /* Store this boolean */
1787 #ifdef BADCHAN
1788     if(*host=='#' || *host == '&' || *host == '+')
1789 #ifndef LOCAL_BADCHAN
1790      return 0;
1791 #else
1792      gtype=1;   /* BAD CHANNEL */
1793 #endif
1794 #endif
1795
1796     for (agline = gtype?badchan:gline, a2gline = NULL; agline; 
1797       agline = agline->next)
1798     {
1799       if (!mmatch(agline->name, user) &&
1800           (ip_mask ? GlineIsIpMask(agline) : !GlineIsIpMask(agline)) &&
1801           !mmatch(agline->host, host))
1802         break;
1803       a2gline = agline;
1804     }
1805
1806     if (!agline)
1807     {
1808 #ifdef OPER_LGLINE
1809       if (priv && active && expire > now)
1810       {
1811         /* Add local G-line */
1812         if (parc < 4 || !strchr(parv[3], ' '))
1813         {
1814           sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
1815               me.name, parv[0], "GLINE");
1816           return 0;
1817         }
1818         add_gline(sptr, ip_mask, host, parv[3], user, expire, 1);
1819       }
1820       else
1821 #endif
1822         sendto_one(cptr, err_str(ERR_NOSUCHGLINE), me.name, parv[0], user,
1823             host);
1824
1825       return 0;
1826     }
1827
1828     if (expire <= agline->expire)
1829       expire = 0;
1830
1831     if ((active == -1 ||
1832         (active ? GlineIsActive(agline) : !GlineIsActive(agline))) &&
1833         expire == 0)
1834     {
1835       /* oper wants a list of one gline only */
1836       sendto_one(cptr, rpl_str(RPL_GLIST), me.name, parv[0], agline->name,
1837           agline->host, agline->expire, agline->reason,
1838           GlineIsActive(agline) ? "" : " (Inactive)");
1839       sendto_one(cptr, rpl_str(RPL_ENDOFGLIST), me.name, parv[0]);
1840       return 0;
1841     }
1842
1843     if (active != -1 &&
1844         (active ? !GlineIsActive(agline) : GlineIsActive(agline)))
1845     {
1846       if (active)               /* reset activation on gline */
1847         SetActive(agline);
1848 #ifdef OPER_LGLINE
1849       else if (GlineIsLocal(agline))
1850       {
1851         /* Remove local G-line */
1852         sendto_op_mask(SNO_GLINE, "%s removed local %s for %s@%s",
1853             parv[0], gtype?"BADCHAN":"GLINE",agline->name, agline->host);
1854 #ifdef GPATH
1855         write_log(GPATH, "# " TIME_T_FMT
1856             " %s!%s@%s removed local %s for %s@%s\n",
1857             TStime(), parv[0], cptr->user->username, cptr->user->host,
1858             gtype?"BADCHAN":"GLINE",
1859             agline->name, agline->host);
1860 #endif /* GPATH */
1861         free_gline(agline, a2gline);    /* remove the gline */
1862         return 0;
1863       }
1864 #endif
1865       else
1866         ClearActive(agline);
1867     }
1868     else
1869       active = -1;              /* for later sendto_ops and logging functions */
1870
1871     if (expire)
1872       agline->expire = expire;  /* reset expiration time */
1873
1874     /* inform the operators what's up */
1875     if (active != -1)
1876     {                           /* changing the activation */
1877       sendto_op_mask(SNO_GLINE, !expire ? "%s %sactivating %s for %s@%s" :
1878           "%s %sactivating %s for %s@%s and "
1879           "resetting expiration time to " TIME_T_FMT,
1880           parv[0], active ? "re" : "de", gtype?"BADCHAN":"GLINE",agline->name,
1881           agline->host, agline->expire);
1882 #ifdef GPATH
1883       write_log(GPATH, !expire ? "# " TIME_T_FMT " %s!%s@%s %sactivating "
1884           "%s for %s@%s\n" : "# " TIME_T_FMT " %s!%s@%s %sactivating %s "
1885           "for %s@%s and resetting expiration time to " TIME_T_FMT "\n",
1886           TStime(), parv[0], cptr->user->username, cptr->user->host,
1887           active ? "re" : "de", gtype?"BADCHAN":"GLINE",agline->name, 
1888           agline->host, agline->expire);
1889 #endif /* GPATH */
1890
1891     }
1892     else if (expire)
1893     {                           /* changing only the expiration */
1894       sendto_op_mask(SNO_GLINE,
1895           "%s resetting expiration time on %s for %s@%s to " TIME_T_FMT,
1896           parv[0], gtype?"BADCHAN":"GLINE",agline->name, agline->host, 
1897           agline->expire);
1898 #ifdef GPATH
1899       write_log(GPATH, "# " TIME_T_FMT " %s!%s@%s resetting expiration "
1900           "time on %s for %s@%s to " TIME_T_FMT "\n", TStime(), parv[0],
1901           cptr->user->username, cptr->user->host,gtype?"BADCHAN":"GLINE",
1902           agline->name, agline->host, agline->expire);
1903 #endif /* GPATH */
1904     }
1905   }
1906
1907   return 0;
1908 }