unrealircd

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

jumpserver.c (7153B)

      1 /*
      2  * JumpServer: This module can redirect clients to another server.
      3  * (C) Copyright 2004-2016 Bram Matthys (Syzop).
      4  *
      5  * This program is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License as published by
      7  * the Free Software Foundation; either version 1, or (at your option)
      8  * any later version.
      9  *
     10  * This program is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  * GNU General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU General Public License
     16  * along with this program; if not, write to the Free Software
     17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     18  */
     19 
     20 #include "unrealircd.h"
     21 
     22 ModuleHeader MOD_HEADER
     23   = {
     24 	"jumpserver",
     25 	"1.1",
     26 	"/jumpserver command",
     27 	"UnrealIRCd Team",
     28 	"unrealircd-6",
     29     };
     30 
     31 /* Forward declarations */
     32 CMD_FUNC(cmd_jumpserver);
     33 int jumpserver_preconnect(Client *);
     34 void jumpserver_free_jss(ModData *m);
     35 
     36 /* Jumpserver status struct */
     37 typedef struct JSS JSS;
     38 struct JSS
     39 {
     40 	char *reason;
     41 	char *server;
     42 	int port;
     43 	char *tls_server;
     44 	int tls_port;
     45 };
     46 
     47 JSS *jss=NULL; /**< JumpServer Status. NULL=disabled. */
     48 
     49 MOD_INIT()
     50 {
     51 	MARK_AS_OFFICIAL_MODULE(modinfo);
     52 	LoadPersistentPointer(modinfo, jss, jumpserver_free_jss);
     53 	CommandAdd(modinfo->handle, "JUMPSERVER", cmd_jumpserver, 3, CMD_USER);
     54 	HookAdd(modinfo->handle, HOOKTYPE_PRE_LOCAL_CONNECT, 0, jumpserver_preconnect);
     55 	return MOD_SUCCESS;
     56 }
     57 
     58 MOD_LOAD()
     59 {
     60 	return MOD_SUCCESS;
     61 }
     62 
     63 MOD_UNLOAD()
     64 {
     65 	SavePersistentPointer(modinfo, jss);
     66 	return MOD_SUCCESS;
     67 }
     68 
     69 static void do_jumpserver_exit_client(Client *client)
     70 {
     71 	if (IsSecure(client) && jss->tls_server)
     72 		sendnumeric(client, RPL_REDIR, jss->tls_server, jss->tls_port);
     73 	else
     74 		sendnumeric(client, RPL_REDIR, jss->server, jss->port);
     75 	exit_client(client, NULL, jss->reason);
     76 }
     77 
     78 static void redirect_all_clients(void)
     79 {
     80 	int count = 0;
     81 	Client *client, *next;
     82 
     83 	list_for_each_entry_safe(client, next, &lclient_list, lclient_node)
     84 	{
     85 		if (IsUser(client) && !IsOper(client))
     86 		{
     87 			do_jumpserver_exit_client(client);
     88 			count++;
     89 		}
     90 	}
     91 	unreal_log(ULOG_INFO, "jumpserver", "JUMPSERVER_REPORT", NULL,
     92 	           "[jumpserver] Redirected $num_clients client(s)",
     93 	           log_data_integer("num_clients", count));
     94 }
     95 
     96 int jumpserver_preconnect(Client *client)
     97 {
     98 	if (jss)
     99 	{
    100 		do_jumpserver_exit_client(client);
    101 		return HOOK_DENY;
    102 	}
    103 	return HOOK_CONTINUE;
    104 }
    105 
    106 void free_jss(void)
    107 {
    108 	if (jss)
    109 	{
    110 		safe_free(jss->server);
    111 		safe_free(jss->reason);
    112 		safe_free(jss->tls_server);
    113 		safe_free(jss);
    114 		jss = NULL;
    115 	}
    116 }
    117 
    118 void jumpserver_free_jss(ModData *m)
    119 {
    120 	free_jss();
    121 }
    122 
    123 CMD_FUNC(cmd_jumpserver)
    124 {
    125 	char *serv, *tlsserv=NULL, *p;
    126 	const char *reason;
    127 	int all=0, port=6667, sslport=6697;
    128 	char request[BUFSIZE];
    129 	char logbuf[512];
    130 
    131 	if (!IsOper(client))
    132 	{
    133 		sendnumeric(client, ERR_NOPRIVILEGES);
    134 		return;
    135 	}
    136 
    137 	if ((parc < 2) || BadPtr(parv[1]))
    138 	{
    139 		if (jss && jss->tls_server)
    140 			sendnotice(client, "JumpServer is \002ENABLED\002 to %s:%d (TLS: %s:%d) with reason '%s'",
    141 				jss->server, jss->port, jss->tls_server, jss->tls_port, jss->reason);
    142 		else
    143 		if (jss)
    144 			sendnotice(client, "JumpServer is \002ENABLED\002 to %s:%d with reason '%s'",
    145 				jss->server, jss->port, jss->reason);
    146 		else
    147 			sendnotice(client, "JumpServer is \002DISABLED\002");
    148 		return;
    149 	}
    150 
    151 	if ((parc > 1) && (!strcasecmp(parv[1], "OFF") || !strcasecmp(parv[1], "STOP")))
    152 	{
    153 		if (!jss)
    154 		{
    155 			sendnotice(client, "JUMPSERVER: No redirect active (already OFF)");
    156 			return;
    157 		}
    158 		free_jss();
    159 		unreal_log(ULOG_INFO, "jumpserver", "JUMPSERVER_DISABLED", client,
    160 		           "[jumpserver] $client.details turned jumpserver OFF");
    161 		return;
    162 	}
    163 
    164 	if (parc < 4)
    165 	{
    166 		/* Waah, pretty verbose usage info ;) */
    167 		sendnotice(client, "Use: /JUMPSERVER <server>[:port] <NEW|ALL> <reason>");
    168 		sendnotice(client, " Or: /JUMPSERVER <server>[:port]/<tlsserver>[:port] <NEW|ALL> <reason>");
    169 		sendnotice(client, "if 'NEW' is chosen then only new (incoming) connections will be redirected");
    170 		sendnotice(client, "if 'ALL' is chosen then all clients except opers will be redirected immediately (+incoming connections)");
    171 		sendnotice(client, "Example: /JUMPSERVER irc2.test.net NEW This server will be upgraded, please use irc2.test.net for now");
    172 		sendnotice(client, "And then for example 10 minutes later...");
    173 		sendnotice(client, "         /JUMPSERVER irc2.test.net ALL This server will be upgraded, please use irc2.test.net for now");
    174 		sendnotice(client, "Use: '/JUMPSERVER OFF' to turn off any redirects");
    175 		return;
    176 	}
    177 
    178 	/* Parsing code follows... */
    179 
    180 	strlcpy(request, parv[1], sizeof(request));
    181 	serv = request;
    182 	
    183 	p = strchr(serv, '/');
    184 	if (p)
    185 	{
    186 		*p = '\0';
    187 		tlsserv = p+1;
    188 	}
    189 	
    190 	p = strchr(serv, ':');
    191 	if (p)
    192 	{
    193 		*p++ = '\0';
    194 		port = atoi(p);
    195 		if ((port < 1) || (port > 65535))
    196 		{
    197 			sendnotice(client, "Invalid serverport specified (%d)", port);
    198 			return;
    199 		}
    200 	}
    201 	if (tlsserv)
    202 	{
    203 		p = strchr(tlsserv, ':');
    204 		if (p)
    205 		{
    206 			*p++ = '\0';
    207 			sslport = atoi(p);
    208 			if ((sslport < 1) || (sslport > 65535))
    209 			{
    210 				sendnotice(client, "Invalid TLS serverport specified (%d)", sslport);
    211 				return;
    212 			}
    213 		}
    214 		if (!*tlsserv)
    215 			tlsserv = NULL;
    216 	}
    217 	if (!strcasecmp(parv[2], "new"))
    218 		all = 0;
    219 	else if (!strcasecmp(parv[2], "all"))
    220 		all = 1;
    221 	else {
    222 		sendnotice(client, "ERROR: Invalid action '%s', should be 'NEW' or 'ALL' (see /jumpserver help for usage)", parv[2]);
    223 		return;
    224 	}
    225 
    226 	reason = parv[3];
    227 
    228 	/* Free any old stuff (needed!) */
    229 	if (jss)
    230 		free_jss();
    231 
    232 	jss = safe_alloc(sizeof(JSS));
    233 
    234 	/* Set it */
    235 	safe_strdup(jss->server, serv);
    236 	jss->port = port;
    237 	if (tlsserv)
    238 	{
    239 		safe_strdup(jss->tls_server, tlsserv);
    240 		jss->tls_port = sslport;
    241 	}
    242 	safe_strdup(jss->reason, reason);
    243 
    244 	/* Broadcast/log */
    245 	if (tlsserv)
    246 	{
    247 		unreal_log(ULOG_INFO, "jumpserver", "JUMPSERVER_ENABLED", client,
    248 		           "[jumpserver] $client.details turned jumpserver ON for $jumpserver_who "
    249 		           "to $jumpserver_server:$jumpserver_port "
    250 		           "[TLS: $jumpserver_tls_server:$jumpserver_tls_port] "
    251 		           "($reason)",
    252 		           log_data_string("jumpserver_who", all ? "ALL CLIENTS" : "all new clients"),
    253 		           log_data_string("jumpserver_server", jss->server),
    254 		           log_data_integer("jumpserver_port", jss->port),
    255 		           log_data_string("jumpserver_tls_server", jss->tls_server),
    256 		           log_data_integer("jumpserver_tls_port", jss->tls_port),
    257 		           log_data_string("reason", jss->reason));
    258 	} else {
    259 		unreal_log(ULOG_INFO, "jumpserver", "JUMPSERVER_ENABLED", client,
    260 		           "[jumpserver] $client.details turned jumpserver ON for $jumpserver_who "
    261 		           "to $jumpserver_server:$jumpserver_port "
    262 		           "($reason)",
    263 		           log_data_string("jumpserver_who", all ? "ALL CLIENTS" : "all new clients"),
    264 		           log_data_string("jumpserver_server", jss->server),
    265 		           log_data_integer("jumpserver_port", jss->port),
    266 		           log_data_string("reason", jss->reason));
    267 	}
    268 
    269 	if (all)
    270 		redirect_all_clients();
    271 }