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