unrealircd

- supernets unrealircd source & configuration
git clone git://git.acid.vegas/unrealircd.git
Log | Files | Refs | Archive | README | LICENSE

trace.c (6322B)

      1 /*
      2  *   IRC - Internet Relay Chat, src/modules/trace.c
      3  *   (C) 2004 The UnrealIRCd Team
      4  *
      5  *   See file AUTHORS in IRC package for additional names of
      6  *   the programmers.
      7  *
      8  *   This program is free software; you can redistribute it and/or modify
      9  *   it under the terms of the GNU General Public License as published by
     10  *   the Free Software Foundation; either version 1, or (at your option)
     11  *   any later version.
     12  *
     13  *   This program is distributed in the hope that it will be useful,
     14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  *   GNU General Public License for more details.
     17  *
     18  *   You should have received a copy of the GNU General Public License
     19  *   along with this program; if not, write to the Free Software
     20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     21  */
     22 
     23 #include "unrealircd.h"
     24 
     25 CMD_FUNC(cmd_trace);
     26 
     27 #define MSG_TRACE 	"TRACE"	
     28 
     29 ModuleHeader MOD_HEADER
     30   = {
     31 	"trace",
     32 	"5.0",
     33 	"command /trace", 
     34 	"UnrealIRCd Team",
     35 	"unrealircd-6",
     36     };
     37 
     38 MOD_INIT()
     39 {
     40 	CommandAdd(modinfo->handle, MSG_TRACE, cmd_trace, MAXPARA, CMD_USER);
     41 	MARK_AS_OFFICIAL_MODULE(modinfo);
     42 	return MOD_SUCCESS;
     43 }
     44 
     45 MOD_LOAD()
     46 {
     47 	return MOD_SUCCESS;
     48 }
     49 
     50 MOD_UNLOAD()
     51 {
     52 	return MOD_SUCCESS;
     53 }
     54 
     55 /*
     56 ** cmd_trace
     57 **	parv[1] = servername
     58 */
     59 CMD_FUNC(cmd_trace)
     60 {
     61 	int  i;
     62 	Client *acptr;
     63 	ConfigItem_class *cltmp;
     64 	const char *tname;
     65 	int  doall, link_s[MAXCONNECTIONS], link_u[MAXCONNECTIONS];
     66 	int  cnt = 0, wilds, dow;
     67 	time_t now;
     68 
     69 	/* This is one of the (few) commands that cannot be handled
     70 	 * by labeled-response because responses from multiple servers
     71 	 * are involved.
     72 	 */
     73 	labeled_response_inhibit = 1;
     74 
     75 	if (parc > 2)
     76 		if (hunt_server(client, NULL, "TRACE", 2, parc, parv))
     77 			return;
     78 
     79 	if (parc > 1)
     80 		tname = parv[1];
     81 	else
     82 		tname = me.name;
     83 
     84 	if (!ValidatePermissionsForPath("client:see:trace:global",client,NULL,NULL,NULL))
     85 	{
     86 		if (ValidatePermissionsForPath("client:see:trace:local",client,NULL,NULL,NULL))
     87 		{
     88 			/* local opers may not /TRACE remote servers! */
     89 			if (strcasecmp(tname, me.name))
     90 			{
     91 				sendnotice(client, "You can only /TRACE local servers as a locop");
     92 				sendnumeric(client, ERR_NOPRIVILEGES);
     93 				return;
     94 			}
     95 		} else {
     96 			sendnumeric(client, ERR_NOPRIVILEGES);
     97 			return;
     98 		}
     99 	}
    100 
    101 	switch (hunt_server(client, NULL, "TRACE", 1, parc, parv))
    102 	{
    103 	  case HUNTED_PASS:	/* note: gets here only if parv[1] exists */
    104 	  {
    105 		  Client *ac2ptr;
    106 
    107 		  ac2ptr = find_client(tname, NULL);
    108 		  sendnumeric(client, RPL_TRACELINK,
    109 		      version, debugmode, tname, ac2ptr->direction->name);
    110 		  return;
    111 	  }
    112 	  case HUNTED_ISME:
    113 		  break;
    114 	  default:
    115 		  return;
    116 	}
    117 
    118 	doall = (parv[1] && (parc > 1)) ? match_simple(tname, me.name) : TRUE;
    119 	wilds = !parv[1] || strchr(tname, '*') || strchr(tname, '?');
    120 	dow = wilds || doall;
    121 
    122 	for (i = 0; i < MAXCONNECTIONS; i++)
    123 		link_s[i] = 0, link_u[i] = 0;
    124 
    125 
    126 	if (doall) {
    127 		list_for_each_entry(acptr, &client_list, client_node)
    128 		{
    129 			if (acptr->direction->local->fd < 0)
    130 				continue;
    131 			if (IsUser(acptr))
    132 				link_u[acptr->direction->local->fd]++;
    133 			else if (IsServer(acptr))
    134 				link_s[acptr->direction->local->fd]++;
    135 		}
    136 	}
    137 
    138 	/* report all direct connections */
    139 
    140 	now = TStime();
    141 	list_for_each_entry(acptr, &lclient_list, lclient_node)
    142 	{
    143 		const char *name;
    144 		const char *class;
    145 
    146 		if (!ValidatePermissionsForPath("client:see:trace:invisible-users",client,acptr,NULL,NULL) && (acptr != client))
    147 			continue;
    148 		if (!doall && wilds && !match_simple(tname, acptr->name))
    149 			continue;
    150 		if (!dow && mycmp(tname, acptr->name))
    151 			continue;
    152 		name = get_client_name(acptr, FALSE);
    153 		class = acptr->local->class ? acptr->local->class->name : "default";
    154 		switch (acptr->status)
    155 		{
    156 			case CLIENT_STATUS_CONNECTING:
    157 				sendnumeric(client, RPL_TRACECONNECTING, class, name);
    158 				cnt++;
    159 				break;
    160 
    161 			case CLIENT_STATUS_HANDSHAKE:
    162 				sendnumeric(client, RPL_TRACEHANDSHAKE, class, name);
    163 				cnt++;
    164 				break;
    165 
    166 			case CLIENT_STATUS_ME:
    167 				break;
    168 
    169 			case CLIENT_STATUS_UNKNOWN:
    170 				sendnumeric(client, RPL_TRACEUNKNOWN, class, name);
    171 				cnt++;
    172 				break;
    173 
    174 			case CLIENT_STATUS_USER:
    175 				/* Only opers see users if there is a wildcard
    176 				 * but anyone can see all the opers.
    177 				 */
    178 				if (ValidatePermissionsForPath("client:see:trace:invisible-users",client,acptr,NULL,NULL) ||
    179 				    (!IsInvisible(acptr) && ValidatePermissionsForPath("client:see:trace",client,acptr,NULL,NULL)))
    180 				{
    181 					if (ValidatePermissionsForPath("client:see:trace",client,acptr,NULL,NULL) || ValidatePermissionsForPath("client:see:trace:invisible-users",client,acptr,NULL,NULL))
    182 						sendnumeric(client, RPL_TRACEOPERATOR,
    183 						    class, acptr->name,
    184 						    GetHost(acptr),
    185 						    (long long)(now - acptr->local->last_msg_received));
    186 					else
    187 						sendnumeric(client, RPL_TRACEUSER,
    188 						    class, acptr->name,
    189 						    acptr->user->realhost,
    190 						    (long long)(now - acptr->local->last_msg_received));
    191 					cnt++;
    192 				}
    193 				break;
    194 
    195 			case CLIENT_STATUS_SERVER:
    196 				sendnumeric(client, RPL_TRACESERVER, class, acptr->local->fd >= 0 ? link_s[acptr->local->fd] : -1,
    197 				    acptr->local->fd >= 0 ? link_u[acptr->local->fd] : -1, name, *(acptr->server->by) ?
    198 				    acptr->server->by : "*", "*", me.name,
    199 				    (long long)(now - acptr->local->last_msg_received));
    200 				cnt++;
    201 				break;
    202 
    203 			case CLIENT_STATUS_LOG:
    204 				sendnumeric(client, RPL_TRACELOG, LOGFILE, acptr->local->port);
    205 				cnt++;
    206 				break;
    207 
    208 			case CLIENT_STATUS_TLS_CONNECT_HANDSHAKE:
    209 				sendnumeric(client, RPL_TRACENEWTYPE, "TLS-Connect-Handshake", name);
    210 				cnt++;
    211 				break;
    212 
    213 			case CLIENT_STATUS_TLS_ACCEPT_HANDSHAKE:
    214 				sendnumeric(client, RPL_TRACENEWTYPE, "TLS-Accept-Handshake", name);
    215 				cnt++;
    216 				break;
    217 
    218 			default:	/* ...we actually shouldn't come here... --msa */
    219 				sendnumeric(client, RPL_TRACENEWTYPE, "<newtype>", name);
    220 				cnt++;
    221 				break;
    222 		}
    223 	}
    224 	/*
    225 	 * Add these lines to summarize the above which can get rather long
    226 	 * and messy when done remotely - Avalon
    227 	 */
    228 	if (!ValidatePermissionsForPath("client:see:trace",client,acptr,NULL,NULL) || !cnt)
    229 		return;
    230 
    231 	for (cltmp = conf_class; doall && cltmp; cltmp = cltmp->next)
    232 	/*	if (cltmp->clients > 0) */
    233 			sendnumeric(client, RPL_TRACECLASS, cltmp->name ? cltmp->name : "[noname]", cltmp->clients);
    234 }