1 char *Version =
2 "tircproxy v0.4.5, Copyleft 2000, Bjarni R. Einarsson <bre@netverjar.is>" ;
3 
4 /*****************************************************************************\
5  *
6  * This is an IRC proxy server. It can be started from inetd to service
7  * IRC requests, or run as a stand-alone daemon.  It can operate with
8  * or without the Linux kernel's transparent proxy feature (or the IPF
9  * filters for *BSD systems).   DCC requests are transparently accepted,
10  * rewritten and proxied for the clients.
11  *
12  * Thanks go to the author of transproxy.c, this program is based on his
13  * code - and without it I would have written a much messier program or
14  * none at all.  This code is distributed under the GPL.
15  *
16  * See the files README, CHANGELOG.txt and BUGS.txt for more info!
17  * Don't forget to edit tircproxy.h to suit your tastes!
18  *
19  * ************************************************************************* *
20  *
21  * Note to hackers, porters, etc.
22  *
23  *   Please, please let me know if you find bugs in my code!
24  *
25 \*****************************************************************************/
26 
27 /* The following is an example of a useful broadcast file.. the format for
28  * /etc/motd.irc is the same (raw IRC server output, that is).
29  *
30  * Keep things short, people have flood protection out there.. and others
31  * are "suppressing" the MOTD!
32 
33 :admin@isp.net 999 * :This is a fake server message!
34 :bofh!admin@isp.net PRIVMSG #notice :The proxy server is about to be shut down!
35 :bofh!admin@isp.net PRIVMSG #notice :Be very afraid!!!
36 
37  */
38 
39 #include <config.h>
40 
41 #include <unistd.h>
42 #include <sys/time.h>
43 #include <sys/socket.h>
44 #include <sys/wait.h>
45 #include <sys/stat.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48 #include <netdb.h>
49 #include <sys/types.h>
50 #include <syslog.h>
51 #include <signal.h>
52 #include <pwd.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <stdarg.h>
56 #include <string.h>
57 #include <ctype.h>
58 #include <fcntl.h>
59 #include <errno.h>
60 
61 #include <tircproxy.h>
62 
63 /*  "Inheritance" of config options.
64 */
65 #ifdef PARANOID
66 # ifndef MIRC_DCC_KLUDGE
67 #  define MIRC_DCC_KLUDGE 1
68 # endif
69 # ifndef NICK_LOG
70 #  define NICK_LOG
71 # endif
72 #endif
73 
74 #ifdef MIRC_DCC_KLUDGE
75 # warning MIRC DCC kludge active
76 #endif
77 #ifdef NICK_LOG
78 # warning Nickname logging active
79 #endif
80 
81 #ifdef CDIR
82 # ifndef IP_TO_UID_PREFIX
83 #  define IP_TO_UID_PREFIX	CDIR CDIR_MAP "-"
84 # endif
85 #endif
86 
87 /* Autoconf stuff
88 */
89 
90 #ifdef HAVE_CRYPT_H
91 # include <crypt.h>
92 #endif
93 
94 #if (HAVE_UDB_H && USE_UDB)
95 # warning Using UDB style IPC for identd etc.
96 # include <udb.h>
97 # undef CDIR
98 # define CDIR 1
99 # undef CDIR_IDENT
100 # define CDIR_IDENT 1
101 # undef IP_TO_UID_PREFIX
102 #else
103 # undef USE_UDB
104 #endif
105 
106 #ifndef INADDR_NONE
107 # define INADDR_NONE -1
108 #endif
109 
110 #if !HAVE_LIBWRAP
111 # undef TCP_WRAPPERS
112 # warning Configuration via /etc/hosts.* not available
113 #else
114 # warning Configuration via /etc/hosts.* available
115 #endif
116 
117 #ifndef IPF
118 # define IPF 0
119 #endif
120 #undef TRANS
121 
122 #if IPF
123 # if HAVE_NETINET_IP_NAT_H
124 #  include <sys/ioctl.h>
125 #  include <net/if.h>
126 #  include <netinet/in_systm.h>
127 #  include <netinet/tcp.h>
128 #  if HAVE_NETINET_IP_FIL_COMPAT_H
129 #	include <netinet/ip_fil_compat.h>
130 #  else
131 #	include <netinet/ip_compat.h>
132 #  endif
133 #  include <netinet/ip_fil.h>
134 #  include <netinet/ip_nat.h>
135 #  include <netinet/ip_state.h>
136 #  include <netinet/ip_proxy.h>
137 #  include <netinet/ip_nat.h>
138 #  include <netinet/ipl.h>
139 #  include <osreldate.h>
140 #  define TRANS 1
141 #  ifndef IPL_NAT
142 #  define IPL_NAT IPNAT_NAME
143 #  endif
144 #  warning IPF transparent proxying available
145 # else
146 #  undef IPF
147 #  define IPF 0
148 #  warning IPF support not available
149 # endif
150 #endif
151 
152 #ifndef LINUX
153 # define LINUX 0
154 #endif
155 
156 #if LINUX
157 # ifndef HAVE_LINUX
158 #  undef LINUX
159 #  define LINUX 0
160 #  warning Linux support not available
161 # else
162 #  warning Linux transparent proxying available (depends on kernel)
163 #  define TRANS 1
164 # endif
165 #endif
166 
167 #if QUIZ_MODE
168 # warning Quiz mode available
169 #else
170 # warning Quiz mode not available
171 #endif
172 
173 /* Some useful definitions, which we might get from the system.
174 */
175 #ifndef MAXLOGNAME
176 # define MAXLOGNAME 64
177 #endif
178 
179 #ifndef PATH_MAX
180 # define PATH_MAX 256
181 #endif
182 
183 /* Do we want to use the TCP wrappers for access control?
184 */
185 #ifdef TCP_WRAPPERS
186 #include "tcpd.h"
187 
188 int allow_severity	= 0;
189 int deny_severity	= 0;
190 int hosts_ctl(char *daemon,
191 	      char *client_name,
192 	      char *client_addr,
193 	      char *client_user);
194 
195 #endif
196 
197 
198 /* Typedefs.
199 */
200 typedef unsigned long	ipaddr_t;
201 
202 
203 /* Macros & definitions.
204 */
205 #define FD_MAX(a,b)		((a) > (b) ? (a) : (b))
206 #define MINUTE			60
207 
208 #define DEBUG_FEATURES		1
209 #define DEBUG_BASIC		2
210 #define DEBUG_TRIVIA		8
211 #define DEBUG_NOFORK		9
212 
213 
214 /* Function prototypes.
215 */
216 static void usage		(char *prog, char *opt);
217 static short get_port_num	(char *portnum);
218 static ipaddr_t get_ip_addr	(char *ipaddr);
219 static uid_t get_user_id	(char *user);
220 static uid_t get_group_id	(uid_t uid);
221 static int bind_to_port		(ipaddr_t bind_ip, short bind_port,
222 				 int backlog, int dlev);
223 static int connect_to_server	(struct sockaddr_in addr);
224 static void lookup_hostname	(struct sockaddr_in *addr, char *hostname,
225 				 int hostlen, int needed);
226 static void server_main_loop	(int sock);
227 static void trans_proxy		(int sock, struct sockaddr_in *addr);
228 static int  copy_loop		(int sock, struct sockaddr_in *from_addr,
229 		      		 struct sockaddr_in *to_addr,
230 		      		 int is_server_connection);
231 static int  copy_once		(int rsock, char *rbuffer, int rbufsize,
232 				 char *rname,
233 		      		 int wsock, char *wlbuffer, int *wlbufpos,
234 				 char *wname,
235 		     		 int is_server_connection, int r_is_client,
236 		     		 int *read_len);
237 static int filtered_write	(int to_sock, char *buff, int blen,
238 			       	 char *leftover, int *llen,
239 			   	 int isclient);
240 static int scan_line		(char *line, int isclient);
241 static int dcc_mangle_filename	(char *filename);
242 static int dcc_resume		(int destport, int resume);
243 static char *proxy_dcc		(int destaddr, int destport, int incoming);
244 static void get_user_name	(struct sockaddr_in *addr);
245 static void change_uid		(void);
246 #ifdef CDIR
247 static void tell_identd		(struct sockaddr_in *, struct sockaddr_in *);
248 static void cleanup_identd	(void);
249 #endif
250 static void broadcast		(int sock, const char *filename);
251 static void alarm_signal	(int sig);
252 static void hup_signal		(int sig);
253 static void chld_signal		(int sig);
254 static void debug_msg		(int lev, int pri, const char *format, ...);
255 #ifdef QUIZ_MODE
256 static void quiz_delay_line	(char *line, char **first, char ***bl);
257 static void quiz_dump_lines	(int sock, char **first, char ***bl);
258 static void quiz_check_auth	(char *pass);
259 static void quiz_msg		(char *message);
260 static void quiz_greet		(void);
261 #endif
262 
263 /* Taken from the RFC 1459 ..
264 */
265 #define LENGTH_NICKNAME		9
266 #define LENGTH_SERVERDATA	512
267 
268 /* These make useful global variables..
269 */
270 char		user_nick[LENGTH_NICKNAME * 2];
271 char            user_name[MAXLOGNAME];
272 char		user_ident_file[PATH_MAX];
273 char		server_tag[64], alarm_in[64];
274 ipaddr_t	clients_ip = INADDR_NONE;
275 char		clients_ip_s[64];
276 int		motd_is_done = 0;
277 
278 /* We need to remember some stuff to support DCC RESUME.
279 ** See: http://www.mirc.co.uk/help/dccresum.txt
280 */
281 #define MAX_DCC_SESSIONS 10
282 time_t	dcc_session_time  [MAX_DCC_SESSIONS];
283 int	dcc_original_port [MAX_DCC_SESSIONS];
284 int	dcc_proxied_port  [MAX_DCC_SESSIONS];
285 
286 /* Quid mode - require a password or an answer to some silly
287 ** question before sending the users' output to the server.
288 */
289 #ifdef QUIZ_MODE
290 # define QUIZ_OFF	0
291 # define QUIZ_ON	1
292 # define QUIZ_READY	2
293 # define QUIZ_FLUSH	3
294 # define QUIZ_S		&from_cli_first, &from_cli_last
295 # define QUIZ_C		&to_cli_first, &to_cli_last
296 char			*from_cli_first = NULL;
297 char			**from_cli_last = NULL;
298 char			*to_cli_first = NULL;
299 char			**to_cli_last = NULL;
300 char			quizfile[PATH_MAX], quiz[512];
301 int			use_unix_passwd = QUIZ_OFF;
302 int			use_quiz_mode = QUIZ_OFF;
303 #endif
304 
305 /*  Configuration variables..
306 */
307 ipaddr_t	bind_ip = INADDR_ANY;
308 ipaddr_t	server_ip = INADDR_NONE;
309 ipaddr_t	visible_ip_i = INADDR_ANY;
310 char		visible_ip_i_s[64];
311 ipaddr_t	visible_ip_o = INADDR_ANY;
312 char		visible_ip_o_s[64];
313 int		throttle_seconds = -1;
314 int		allow_dcc_send = 1;
315 int		allow_dcc_chat = 1;
316 int		allow_dcc_unknown = 1;
317 short		server_port = -1;
318 int		broadcast_flag = 0;
319 int		not_an_irc_proxy = 0;
320 int		use_dcc_mangling = 1;
321 int		use_syslog = 1;
322 int		debug_level = 0;
323 int		use_anonymity = 0;
324 int		anon_notval = 0;
325 #ifdef PARANOID
326 int		use_paranoid = 1;
327 #endif
328 #ifdef MIRC_DCC_KLUDGE
329 int		use_mirc_dcc_kludge = 1;
330 #endif
331 #ifdef NICK_LOG
332 int		use_nick_log = 1;
333 #endif
334 #ifdef TCP_WRAPPERS
335 int		use_tcp_wrappers = 1;
336 #endif
337 #ifdef CDIR
338 int	   	use_cdir = 1;
339 #endif
340 #ifdef USE_UDB
341 struct udb_connection conn;
342 #endif
343 
344 
345 /* Main!
346 */
main(int argc,char ** argv)347 int main(int argc, char **argv)
348 {
349 	int					arg;
350 	int					run_as_server = 0;
351 	short					bind_port = -1;
352 	uid_t					run_uid = 0;
353 	gid_t					run_gid = 0;
354 	int					sock;
355 	struct sockaddr_in		    	addr;
356 	int					len;
357 
358 	/* Parse the command line arguments.
359 	*/
360 	while ((arg = getopt(argc, argv, "ab:d:h?i:o:pq:r:s:t:CDHIKLMNOQRSU")) != EOF)
361 	{
362 	   	switch (arg)
363 		{
364 
365 		case 'a':
366                     	use_anonymity = 1;
367 			break;
368 		case 'b':
369                     	bind_ip = get_ip_addr(optarg);
370 			break;
371 		case 'd':
372 #ifdef TIRC_DEBUG
373 		   	debug_level = atoi(optarg);
374 #else
375 		   	usage(argv[0],"Feature DEBUG not available.");
376 #endif
377 			break;
378 		case 'h':
379 		case '?':
380 			usage(argv[0], NULL);
381 			break;
382 		case 'i':
383 			visible_ip_i = get_ip_addr(optarg);
384 			break;
385 		case 'o':
386 			visible_ip_o = get_ip_addr(optarg);
387 			break;
388 		case 'p':
389 #ifdef QUIZ_MODE
390 		   	use_quiz_mode = use_unix_passwd = QUIZ_ON;
391 		   	if (getuid()) fprintf(stderr,
392 				"Warning: Not running as root, may not be able to check passwords!\n");
393 #else
394 		   	usage(argv[0],"Feature QUIZ_MODE not active.");
395 #endif
396 		   	break;
397 		case 'q':
398 #ifdef QUIZ_MODE
399 		   	use_quiz_mode = QUIZ_ON;
400 		   	strncpy(quizfile, optarg, PATH_MAX);
401 			quizfile[PATH_MAX-1] = '\0';
402 #else
403 		   	usage(argv[0],"Feature QUIZ_MODE not active.");
404 #endif
405 		   	break;
406 		case 'r':
407 			run_uid = get_user_id(optarg);
408 			run_gid = get_group_id(run_uid);
409 			break;
410 		case 's':
411 			run_as_server = 1;
412 			bind_port = get_port_num(optarg);
413 			break;
414 
415 		case 't':
416 			throttle_seconds = atoi(optarg);
417 			break;
418 
419 		case 'C':
420 			allow_dcc_chat = 0;
421 			break;
422 
423 		case 'D':
424 #ifdef NICK_LOG
425 		   	use_nick_log = 0;
426 #else
427 		   	usage(argv[0],"Feature NICK_LOG not active.");
428 #endif
429 		   	break;
430 		case 'H':
431 #ifdef TCP_WRAPPERS
432 			use_tcp_wrappers = 0;
433 #else
434 		   	usage(argv[0],"Feature TCP_WRAPPERS not active.");
435 #endif
436 		   	break;
437 		case 'I':
438 		case 'O': /* backwards compatibility ... */
439 #ifdef CDIR
440 		   	use_cdir = 0;
441 #else
442 		   	usage(argv[0],"Neither CDIR nor USE_UDB compiled in, sorry.");
443 #endif
444 		   	break;
445 		case 'K':
446 #ifdef MIRC_DCC_KLUDGE
447 			use_mirc_dcc_kludge = 0;
448 #else
449 		   	usage(argv[0],"Feature MIRC_DCC_KLUDGE not active.");
450 #endif
451 		   	break;
452 		case 'L':
453 			use_syslog = 0;
454 			break;
455 		case 'M':
456 			use_dcc_mangling = 0;
457 			break;
458 
459 		case 'N':
460 		   	not_an_irc_proxy = 1;
461 		   	break;
462 		case 'R':
463 #ifdef PARANOID
464 		   	use_paranoid = 0;
465 #else
466 		   	usage(argv[0],"Feature PARANOID not active.");
467 #endif
468 		   	break;
469 		case 'S':
470 		   	allow_dcc_send = 0;
471 		   	break;
472 		case 'U':
473 			allow_dcc_unknown = 0;
474 			break;
475 		}
476 	}
477 
478    	/* Set a few variables to 'default' values.
479 	*/
480    	if ((bind_ip != INADDR_ANY) && (visible_ip_i == INADDR_ANY))
481      		visible_ip_i = bind_ip;
482 
483 	*user_ident_file = *user_name = *user_nick = '\0';
484 
485 	/* Process the remaining command line arguments.
486 	*/
487 	for (; optind < argc; ++optind)
488 	{
489 		if (server_ip == INADDR_NONE)
490 		{
491 			server_ip = get_ip_addr(argv[optind]);
492 		}
493 		else if (server_port == -1)
494 		{
495 			server_port = get_port_num(argv[optind]);
496 		}
497 		else
498 		{
499 			usage(argv[0], "Extra arguments were specified.");
500 		}
501 	}
502 
503    	if (server_ip == INADDR_NONE)
504 	{
505 #ifndef TRANS
506 	   	usage(argv[0], "No remote server specified!");
507 #else
508 	   	if ((visible_ip_i == INADDR_ANY) &&
509 		    (allow_dcc_send | allow_dcc_chat | allow_dcc_unknown) &&
510 		    (!not_an_irc_proxy))
511 		{
512 		   	usage(argv[0], "No internal address specified, DCC would break!");
513 		}
514 
515 	   	fprintf(stderr,
516 				"No remote server specified, transparent operation assumed.\n");
517 #endif
518 	}
519    	else
520 	{
521 		if (server_port == -1)
522 		{
523 		   	server_port = 6667;
524 		   	fprintf(stderr,"No remote port specified, defaulting to 6667\n");
525 		}
526 	}
527 
528    	/* Create a "server tag" for this proxy.  This is used for preventing
529 	** loops, while allowing proxy-to-proxy operation.
530 	*/
531 	{
532 	   	char hostname[128];
533 	   	gethostname(hostname, 127);
534 
535 		/* server_tag is 64 bytes - this is safe */
536    		sprintf(server_tag, "X-tircproxy[%d/%.10s]\n",
537 				getpid(), hostname );
538 	}
539 
540 #ifdef USE_UDB
541 	/* Aquire handles to the UDB shared memory.
542 	*/
543 	udb_init(UDB_ENV_BASE_KEY);
544 #endif
545 
546 	/* See if we should run as a server.
547 	*/
548 	if (run_as_server)
549 	{
550 	   	/* Randomize the anonymouse userid.
551 		*/
552 	   	if (use_anonymity)
553 	     	{
554 		   	srand(time((time_t) NULL));
555 		   	anon_notval = rand();
556 		}
557 
558 		/* Start by binding to the port, the child inherits this socket.
559 		*/
560 		sock = bind_to_port(bind_ip, bind_port, SOMAXCONN, 0);
561 		if (sock < 0)
562 		{
563 			usage(argv[0], "Failed to bind to port, is another tircproxy still running?");
564 		}
565 
566 		/* Start a server process. When DEBUG is defined, and the
567 		** debug level is high, just run in the foreground.
568 		*/
569 #ifdef TIRC_DEBUG
570 		switch ((debug_level >= DEBUG_NOFORK) ? 0 : fork())
571 #else
572 		switch (fork())
573 #endif
574 		{
575 		case -1:
576 			perror("fork()");
577 			exit(1);
578 
579 		case 0:
580 			/* Open syslog for logging errors.
581 			*/
582 		   	if ((use_syslog) && (debug_level < DEBUG_NOFORK))
583 			   	openlog((not_an_irc_proxy) ? "proxy" : "tircproxy",
584 					LOG_PID, LOG_DAEMON);
585 
586 			/* Ignore some signals.
587 			*/
588 			signal(SIGHUP, SIG_IGN);
589 #ifdef TIRC_DEBUG
590 		   	if (debug_level < DEBUG_NOFORK)
591 #else
592 				signal(SIGINT, SIG_IGN);
593 #endif
594 			signal(SIGQUIT, SIG_IGN);
595 			signal(SIGTSTP, SIG_IGN);
596 			signal(SIGCONT, SIG_IGN);
597 			signal(SIGPIPE, SIG_IGN);
598 			signal(SIGALRM, alarm_signal);
599 
600 		   	if (run_gid)
601 		     	{
602 				/* Drop back to an untrusted user.
603 				*/
604 				setgid(run_gid);
605 				setuid(run_uid);
606 
607 				/* Start a new session and group.
608 				*/
609 				setsid();
610 #ifdef HAVE_LINUX
611 				setpgrp();
612 #endif
613 			}
614 
615 			/* Handle the server main loop.
616 			*/
617 			server_main_loop(sock);
618 
619 			/* Should never exit.
620 			*/
621 			closelog();
622 			exit(1);
623 		}
624 
625 		/* Parent exits at this stage.
626 		*/
627 		exit(0);
628 	}
629 
630 	/* Open syslog for logging errors.
631 	*/
632    	if ((use_syslog) && (debug_level < DEBUG_NOFORK))
633 	  	openlog((not_an_irc_proxy) ? "proxy" : "tircproxy",
634 			LOG_PID, LOG_DAEMON);
635 
636 	/* We are running from inetd so find the peer address.
637 	*/
638 	len = sizeof(addr);
639 	if (getpeername(STDIN_FILENO, (struct sockaddr *)&addr, &len) < 0)
640 	{
641 		debug_msg(0, LOG_ERR, "getpeername(): %.256s", strerror(errno));
642 		closelog();
643 
644 		usage(argv[0], NULL);
645 	}
646 
647    	/* Randomize (well, not really..) the anonymouse userid.
648 	*/
649    	if (use_anonymity) anon_notval = (time((time_t) NULL) >> 17);
650 
651    	/* Make note of the client's IP address.
652 	*/
653         clients_ip = addr.sin_addr.s_addr;
654        	lookup_hostname(&addr, clients_ip_s, sizeof(clients_ip_s), 0);
655 
656 	/* Set the keepalive socket option to on.
657 	*/
658 	{
659 		int on = 1;
660 		setsockopt(STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof(on));
661 	}
662 
663 	/* We are running from inetd so process stdin.
664 	*/
665 	trans_proxy(STDIN_FILENO, &addr);
666 	closelog();
667 
668 	return (0);
669 }
670 
671 
672 /* Print some basic help information.
673 */
usage(char * prog,char * opt)674 static void usage(char *prog, char *opt)
675 {
676 	fprintf(stderr,"%s\n\n\
677 Usage: %s [switches..] [options..] [ircserver [ircport]]\n\
678 \n\
679 Options:\n",Version,prog);
680 #ifdef TIRC_DEBUG
681 	fprintf(stderr,
682 "   -d level    Set debug level (0=nothing .. 8=everything, 9=foreground).\n");
683 #endif
684 	fprintf(stderr,"\
685    -s port     Run as a server bound to the specified port.\n\
686    -b ipaddr   Bind to the specified ipaddr in server mode.\n\
687    -i ipaddr   Internal IP, needed for incoming DCCs (when transparent).\n\
688    -o ipaddr   Visible IP, used for connecting to the IRC server (and others).\n");
689 #ifdef QUIZ_MODE
690 	fprintf(stderr,"\
691    -p          Require a valid Unix password for access.\n\
692    -q file     Read a list of 'quizzes' from the named file.\n");
693 #endif
694 	fprintf(stderr,"\
695    -a          Anonymous mode, hide as much info about the user as possible.\n\
696    -r user     Run as the specified user in server mode.\n\
697    -t n	       Force a sleep(1) between connections under n seconds apart.\n\
698 Switches:\n\
699    -M          Disable DCC SEND filename mangling/censorship.\n\
700    -C          Disallow DCC CHAT.\n\
701    -S          Disallow DCC file transmissions (SEND, TSEND, etc.).\n\
702    -U          Disallow unknown DCC requests.\n\
703    -L          Log to stderr instead of syslog.\n\
704    -N          Not an IRC proxy, disable all neat-o IRC stuff\n");
705 #ifdef CDIR
706 	fprintf(stderr,"\
707    -I          Do not attempt to communicate with the identd.\n");
708 #endif
709 #ifdef PARANOID
710 	fprintf(stderr,"\
711    -R          Relaxed, allows proxy service to IPs we can't map to a UID.\n");
712 #endif
713 #ifdef NICK_LOG
714 	fprintf(stderr,"\
715    -D          Don't log clients' nicknames in syslog.\n");
716 #endif
717 #ifdef MIRC_DCC_KLUDGE
718 	fprintf(stderr,"\
719    -K          Disable the \"mIRC DCC kludge\" (read the documentation).\n");
720 #endif
721 #ifdef TCP_WRAPPERS
722 	fprintf(stderr,"\
723    -H          Ignore /etc/hosts.allow and /etc/hosts.deny.\n");
724 #endif
725 	fprintf(stderr,"\n\
726 By default all features enabled at compile-time are active.  In server mode\n\
727 the -s flag is mandatory.\n");
728 
729 #ifdef TRANS
730  	fprintf(stderr,"\n\
731 If no IRC server/port pair is specified the proxy assumes it is running in\n\
732 transparent mode.  This requires support from the Linux kernel or a working\n\
733 ipf filter installation!\n");
734 #endif
735 
736 	if (opt)
737  	{
738 		fprintf(stderr,"\nERROR:  %s\n", opt);
739 	}
740 
741 	exit(1);
742 }
743 
744 
745 /* Return the port number, in network order, of the specified service.
746 */
get_port_num(char * portnum)747 static short get_port_num(char *portnum)
748 {
749 	char			*digits = portnum;
750 	struct servent		*serv;
751 	short			port;
752 
753 	for (port = 0; isdigit(*digits); ++digits)
754 	{
755 		port = (port * 10) + (*digits - '0');
756 	}
757 
758 	if ((*digits != '\0') || (port <= 0))
759 	{
760 		if ((serv = getservbyname(portnum, "tcp")) != NULL)
761 		{
762 			port = ntohs(serv->s_port);
763 		}
764 		else
765 		{
766 			port = -1;
767 		}
768 		endservent();
769 	}
770 
771 #ifdef TIRC_DEBUG
772    	debug_msg(DEBUG_TRIVIA, LOG_DEBUG,
773 		  "Port lookup %s -> %hd\n", portnum, port);
774 #endif
775 
776 	return (port);
777 }
778 
779 
780 /* Return the IP address of the specified host.
781 */
get_ip_addr(char * ipaddr)782 static ipaddr_t get_ip_addr(char *ipaddr)
783 {
784 	struct hostent	*host;
785 	ipaddr_t		ip;
786 
787 	if (((ip = inet_addr(ipaddr)) == INADDR_NONE) &&
788 	    (strcmp(ipaddr, "255.255.255.255") != 0))
789 	{
790 		if ((host = gethostbyname(ipaddr)) != NULL)
791 		{
792 			memcpy(&ip, host->h_addr, sizeof(ip));
793 		}
794 		endhostent();
795 	}
796 
797 #ifdef TIRC_DEBUG
798    	debug_msg(DEBUG_BASIC, LOG_DEBUG,
799 		  "IP lookup %s -> 0x%08lx\n", ipaddr, ip);
800 #endif
801 
802 	return (ip);
803 }
804 
805 
806 /* Find the userid of the specified user.
807 */
get_user_id(char * user)808 static uid_t get_user_id(char *user)
809 {
810 	struct passwd	*pw;
811 	uid_t			uid;
812 
813 	if ((pw = getpwnam(user)) != NULL)
814 	{
815 		uid = pw->pw_uid;
816 	}
817 	else if (*user == '#')
818 	{
819 		uid = (uid_t)atoi(&user[1]);
820 	}
821 	else
822 	{
823 		uid = -1;
824 	}
825 
826 #ifdef TIRC_DEBUG
827    	debug_msg(DEBUG_BASIC, LOG_DEBUG,
828 	    "User lookup %s -> %d\n", user, uid);
829 #endif
830 
831 	endpwent();
832 
833 	return (uid);
834 }
835 
836 
837 /* Find the groupid of the specified user.
838 */
get_group_id(uid_t uid)839 static uid_t get_group_id(uid_t uid)
840 {
841 	struct passwd	*pw;
842 	gid_t			gid;
843 
844 	if ((pw = getpwuid(uid)) != NULL)
845 	{
846 		gid = pw->pw_gid;
847 	}
848 	else
849 	{
850 		gid = -1;
851 	}
852 
853 #ifdef TIRC_DEBUG
854    	debug_msg(DEBUG_TRIVIA, LOG_DEBUG,
855 		  "Group lookup %d -> %d\n", uid, gid);
856 #endif
857 
858 	endpwent();
859 
860 	return (gid);
861 }
862 
863 
864 /* Bind to the specified ip and port.
865 */
bind_to_port(ipaddr_t bind_ip,short bind_port,int backlog,int dlev)866 static int bind_to_port(ipaddr_t bind_ip, short bind_port, int backlog, int dlev)
867 {
868 	struct sockaddr_in	addr;
869 	int			sock;
870 
871 	/* Allocate a socket.
872 	*/
873 	if ((sock = socket(AF_INET, SOCK_STREAM,
874 			getprotobyname("tcp")->p_proto)) < 0)
875 	{
876      		debug_msg(dlev, LOG_WARNING, "socket(): %d - %.256s", errno, strerror(errno));
877 	   	return(-1);
878 	}
879 
880 #ifdef TIRC_DEBUG
881 	/* Set the SO_REUSEADDR option for debugging.
882 	*/
883 	if (debug_level >= DEBUG_NOFORK) {
884 	 	int on = 1;
885 
886 		setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
887 	}
888 #endif
889 
890 	/* Set the address to listen to.
891 	*/
892    	memset(&addr, '\0', sizeof(addr));
893 	addr.sin_family = AF_INET;
894 	addr.sin_port = htons(bind_port);
895 	addr.sin_addr.s_addr = bind_ip;
896 
897 	/* Bind our socket to the above address.
898 	*/
899 	if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
900 	{
901 		debug_msg(dlev, LOG_WARNING, "bind(): %d - %.256s", errno, strerror(errno));
902 	   	return(-1);
903 	}
904 
905 	/* Establish a large listen backlog.
906 	*/
907 	if (listen(sock, backlog) < 0)
908 	{
909 		debug_msg(dlev, LOG_WARNING, "listen(): %d - %.256s", errno, strerror(errno));
910 	   	return(-1);
911 	}
912 
913 	return (sock);
914 }
915 
916 
917 /* Connect to the a server.
918 */
connect_to_server(struct sockaddr_in addr)919 static int connect_to_server(struct sockaddr_in addr)
920 {
921    	struct sockaddr_in my_addr;
922 	int	sock;
923 
924 	/* Allocate a socket.
925 	*/
926 	if ((sock = socket(AF_INET, SOCK_STREAM,
927 					   getprotobyname("tcp")->p_proto)) < 0)
928 	{
929 		debug_msg(0, LOG_WARNING, "socket(): .%256s", strerror(errno));
930 		return (-1);
931 	}
932 
933 	/* Set the address to connect to, and the address to connect from.
934 	*/
935 	addr.sin_family = AF_INET;
936 
937    	memset(&my_addr, '\0', sizeof(my_addr));
938 	my_addr.sin_family = AF_INET;
939 	my_addr.sin_port = 0;
940 	my_addr.sin_addr.s_addr = visible_ip_o;
941 
942    	/* Bind to the address we want to use.
943 	*/
944    	if (bind(sock, (struct sockaddr *)&my_addr, sizeof(my_addr)) < 0)
945 	  debug_msg(0, LOG_WARNING, "bind(): %d - %.256s",
946 				errno, strerror(errno));
947 
948    	/* Connect our socket to the above address.
949 	*/
950 	if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
951 	{
952 		debug_msg(0, LOG_WARNING, "connect(): %.256s", strerror(errno));
953 		return (-1);
954 	}
955 
956 	/* Set the keepalive socket option to on.
957 	*/
958 	{
959 		int on = 1;
960 		setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof(on));
961 	}
962 
963 	return (sock);
964 }
965 
966 
967 /* Translate a sockaddr_in structure into a usable ASCII hostname.
968 */
lookup_hostname(struct sockaddr_in * addr,char * hostname,int hostlen,int needed)969 static void lookup_hostname(struct sockaddr_in *addr, char *hostname,
970 						int hostlen, int needed)
971 {
972 	struct hostent *host;
973 
974    	if (needed)
975      	{
976 		/*  Attempt a DNS lookup..
977 		*/
978 	   	if ((host = gethostbyaddr((char *)&addr->sin_addr,
979 					 	sizeof(addr->sin_addr),
980 					  	AF_INET)) != NULL)
981 	     	{
982 			strncpy(hostname, host->h_name, hostlen);
983 		   	hostname[hostlen - 1] = '\0';
984 		   	return;
985 		}
986 	}
987 
988 	/* Get the hostname IP in dotted decimal in case the lookup fails.
989 	*/
990 	strncpy(hostname, inet_ntoa(addr->sin_addr), hostlen);
991 	hostname[hostlen - 1] = '\0';
992 }
993 
994 
995 /* This is the main loop when running as a server.
996 */
server_main_loop(int sock)997 static void server_main_loop(int sock)
998 {
999 	int					new_sock;
1000 	struct sockaddr_in			addr;
1001 	int					len;
1002    	time_t					last_time, this_time;
1003  	int				  	delay;
1004 
1005 	/* Call cleanup func on SIGCHLD.
1006 	*/
1007 	signal(SIGCHLD, chld_signal);
1008 
1009    	last_time = (time_t) 0;
1010    	delay = 0;
1011 
1012 	for (;;)
1013 	{
1014 		/* Accept an incoming connection.
1015 		*/
1016 		len = sizeof(addr);
1017 		while ((new_sock =
1018 			accept(sock, (struct sockaddr *)&addr, &len)) < 0)
1019 		{
1020 			/* Connection resets are common enough to log them as debug only.
1021 			*/
1022 			debug_msg(0, (errno == ECONNRESET ? LOG_DEBUG : LOG_ERR), "accept(): %.256s", strerror(errno));
1023 		}
1024 
1025 	   	/* At most send the server one connection every
1026 		** throttle_seconds seconds.
1027 		*/
1028 	   	this_time = time((time_t) NULL);
1029 	   	if (this_time <= last_time+delay+throttle_seconds)
1030 	     		delay++;
1031 		else	delay = 0;
1032 	   	last_time = this_time;
1033 
1034 	   	/* Make note of the client's IP address.
1035 		*/
1036 	        clients_ip = addr.sin_addr.s_addr;
1037 	       	lookup_hostname(&addr, clients_ip_s, sizeof(clients_ip_s), 0);
1038 
1039 		/* Create a new process to handle the connection.
1040 		*/
1041 		switch (fork())
1042 		{
1043 		case -1:
1044 			/* Under load conditions just ignore new connections.
1045 			*/
1046 			break;
1047 
1048 		case 0:
1049 			/* Start the proxy work in the new socket.
1050 			*/
1051 		   	broadcast_flag = 0;
1052        		  	if (delay) {
1053 				debug_msg(0, LOG_DEBUG,"Delaying connection %d seconds..",delay);
1054 				sleep(delay);
1055 			}
1056 			trans_proxy(new_sock, &addr);
1057 			close(new_sock);
1058 			closelog();
1059 			exit(0);
1060 		}
1061 
1062 		/* Close the socket as the child does the handling.
1063 		*/
1064 		close(new_sock);
1065 	}
1066 }
1067 
1068 
1069 /* Handle connections transparently or otherwise..
1070 */
trans_proxy(int sock,struct sockaddr_in * from_addr)1071 static void trans_proxy(int sock, struct sockaddr_in *from_addr)
1072 {
1073 	struct sockaddr_in			to_addr;
1074 	int					to_len;
1075 #if IPF
1076 #if __FreeBSD_version >=600024
1077 	ipfobj_t        obj;
1078 #endif
1079 	struct sockaddr_in                      socketin, sloc;
1080 	natlookup_t				natlook;
1081 	natlookup_t                             *natlookp = &natlook;
1082 	int                                     fd;
1083 #endif
1084 
1085    	/* Give this thing 10 minutes to get started (paranoia).
1086 	*/
1087 	signal(SIGALRM, alarm_signal);
1088    	alarm(10*MINUTE);
1089    	strcpy(alarm_in, "trans_proxy");
1090 
1091    	/*  Check who the client is.
1092 	*/
1093    	get_user_name(from_addr);
1094 
1095 #ifdef TCP_WRAPPERS
1096 	if (use_tcp_wrappers)
1097      	{
1098 		char host_ip[64], host_name[64];
1099 
1100    		/* Lookup an ASCII representation of the host's IP address,
1101 		** and attempt to look up it's FQDN as well (DNS).
1102        		*/
1103        		lookup_hostname(from_addr, host_ip, sizeof(host_ip), 0);
1104        		lookup_hostname(from_addr, host_name, sizeof(host_name), 1);
1105 
1106    		/*  Check if the calling host is allowed to use the proxy.
1107 		*/
1108        		if (!hosts_ctl((not_an_irc_proxy) ? "proxy" : "tircproxy",
1109 			       host_name, host_ip, user_name))
1110 	     	{
1111 		   	debug_msg(0, LOG_INFO,
1112 			       	"Denied access to: %.32s@%.128s [%.96s]",
1113 			       		user_name, host_name, host_ip);
1114 		     	return;
1115 		}
1116 	}
1117 #endif
1118 
1119    	/* Are we running in transparent mode?
1120 	*/
1121    	if (server_ip == INADDR_NONE)
1122      	{
1123 	        /* There are two completely different ways to do this, one
1124 		** based on linux transparent proxying the other based on
1125 		** ipf transparent proyxing, only one is used
1126 		*/
1127 #if LINUX
1128                 /* The Linux method:
1129 		**
1130 		** The first thing we do is get the IP address that the client was
1131 		** trying to connected to. Here lies part of the magic. Normally
1132 		** getsockname returns our address, but not with transparent proxying.
1133 		*/
1134 		to_len = sizeof(to_addr);
1135 		if (getsockname(sock, (struct sockaddr *)&to_addr, &to_len) < 0)
1136 		{
1137 			debug_msg(0, LOG_ERR, "getsockname(): %.256s", strerror(errno));
1138 			return;
1139 		}
1140 #else
1141 # if IPF
1142 	   	/* This is the ipf method
1143 		*/
1144                 to_len = sizeof(socketin);
1145                 if (getpeername(sock, (struct sockaddr *)&socketin, &to_len) == -1)
1146 	     	{
1147                 	perror("getpeername");
1148                 	exit(-1);
1149                 }
1150 
1151                 to_len = sizeof(socketin);
1152                 if (getsockname(sock, (struct sockaddr *)&sloc, &to_len) == -1)
1153 	     	{
1154                 	perror("getsockname");
1155                 	exit(-1);
1156                 }
1157 
1158 #if __FreeBSD_version >=600024
1159 		bzero(&obj, sizeof(obj));
1160 		obj.ipfo_rev = IPFILTER_VERSION;
1161 		obj.ipfo_size = sizeof(natlook);
1162 		obj.ipfo_ptr = &natlook;
1163 		obj.ipfo_type = IPFOBJ_NATLOOKUP;
1164 #endif
1165                 bzero((char *)&natlook, sizeof(natlook));
1166                 natlook.nl_outip = socketin.sin_addr;
1167                 natlook.nl_inip = sloc.sin_addr;
1168                 natlook.nl_flags = IPN_TCP;
1169                 natlook.nl_outport = socketin.sin_port;
1170                 natlook.nl_inport = sloc.sin_port;
1171 
1172                 fd = open(IPL_NAT, O_RDONLY);
1173 #if __FreeBSD_version >=600024
1174 		if (ioctl(fd, SIOCGNATL, &obj) == -1)
1175 #else
1176 		if (ioctl(fd, SIOCGNATL, &natlookp) == -1)
1177 #endif
1178 	     	{
1179                 	perror("ioctl(SIOCGNATL)");
1180                 	exit(-1);
1181                 }
1182                 close(fd);
1183 
1184 	   	/* [ The following is WEIRD.  Why the htons(ntohs()) ??
1185 		**   And why the getip..(inet_ntoa()) ??? ]
1186 		*/
1187 	   	memset(&to_addr, '\0', sizeof(to_addr));
1188                 to_addr.sin_family = AF_INET;
1189                 to_addr.sin_port = htons(ntohs(natlook.nl_realport));
1190                 to_addr.sin_addr.s_addr = get_ip_addr(inet_ntoa(natlook.nl_realip));
1191 # endif /* IFP */
1192 #endif /* LINUX */
1193 	}
1194    	else
1195      	{
1196 	   	/* Ok, not transparent, we'll connect to the specified server.
1197 		*/
1198 	   	memset(&to_addr, '\0', sizeof(to_addr));
1199 		to_addr.sin_family = AF_INET;
1200 		to_addr.sin_port = htons(server_port);
1201 		to_addr.sin_addr.s_addr = server_ip;
1202 	}
1203 
1204    	/*  Drop root privs if we have them.
1205 	*/
1206    	change_uid();
1207 
1208         signal(SIGHUP, hup_signal);
1209 
1210    	debug_msg(0, LOG_DEBUG,
1211 	       	"Copied %d bytes, exiting.",
1212 	       	copy_loop(sock, from_addr, &to_addr, !not_an_irc_proxy));
1213 
1214 #ifdef CDIR_IDENT
1215    	if (use_cdir)
1216      		cleanup_identd();
1217 #endif
1218 }
1219 
1220 
1221 /* Perform the proxy activity itself.
1222 */
copy_loop(int sock,struct sockaddr_in * from_addr,struct sockaddr_in * to_addr,int is_server_connection)1223 static int copy_loop(int sock, struct sockaddr_in *from_addr,
1224 		      		struct sockaddr_in *to_addr,
1225 		      		int is_server_connection)
1226 {
1227 	int					server,junk;
1228    	struct sockaddr_in			ourend, ourend_i;
1229    	char					blurb[64];
1230 	char					from_host[64];
1231 	char					to_host[64];
1232 	static char				headers[16384 + 1];
1233 	static char				ser_left[16384 + 1];
1234 	static char				cli_left[16384 + 1];
1235    	int					ser_ln = 0;
1236      	int					cli_ln = 0;
1237    	int					select_loop;
1238 	int					max_fd;
1239 	fd_set					read_fd;
1240 	int					read_len;
1241    	int					motd_sent = 0;
1242    	int					copied_bytes = 0;
1243 
1244 	/* Allow 3 minutes for things to get properly started.
1245 	*/
1246 	signal(SIGALRM, alarm_signal);
1247    	alarm(3*MINUTE);
1248 	strcpy(alarm_in, "copy_loop: starting");
1249 
1250    	/* Lookup an ASCII representation of the host's IP address.
1251     */
1252 	lookup_hostname(from_addr, from_host, sizeof(from_host), 0);
1253 	lookup_hostname(to_addr, to_host, sizeof(to_host), 0);
1254 
1255 	/* Read the first couple of lines from the client, take a
1256 	** peek.  Check if the server is looping.
1257 	*/
1258    	if (is_server_connection)
1259 	{
1260 #ifdef TIRC_DEBUG
1261 		debug_msg(DEBUG_BASIC, LOG_DEBUG,
1262 				  "Checking if this is a loopy server..");
1263 #endif
1264 	   	server = read_len = -1;
1265 		copy_once(sock, headers, sizeof(headers), "client",
1266 				  server, ser_left, &ser_ln, "server",
1267 				  is_server_connection, 1,
1268 				  &read_len);
1269 
1270 		if (read_len <= 0) return 0;
1271 
1272 	   	strncpy(blurb,headers,63);
1273 	   	if (strstr(blurb,server_tag) != NULL)
1274 	     	{
1275 		   	debug_msg(0, LOG_INFO, "Looping detected, terminating!");
1276 		   	return 0;
1277 		}
1278 	}
1279 
1280 	/* Connect to the server (or die).
1281 	*/
1282 	if ((server = connect_to_server(*to_addr)) < 0) return 0;
1283    	junk = sizeof(ourend);
1284 	strcpy(alarm_in, "copy_loop: getsockname 1");
1285    	getsockname(server, (struct sockaddr *) &ourend, &junk);
1286 
1287 #ifdef CDIR_IDENT
1288 	/* Tell the ident server which user this connection really belongs to.
1289 	**
1290 	** Note: This may be a race between us and the remote IRC server,
1291 	**       depending on the implementation of the ident server.
1292 	*/
1293    	if (use_cdir && is_server_connection) tell_identd(&ourend, to_addr);
1294 #endif
1295 
1296 	strcpy(alarm_in, "copy_loop: getsockname 2");
1297    	getsockname(sock, (struct sockaddr *) &ourend_i, &junk);
1298 
1299    	/* Record what IP addresses we're using.
1300 	*/
1301 	visible_ip_o = ourend.sin_addr.s_addr;
1302 	lookup_hostname(&ourend, visible_ip_o_s, sizeof(visible_ip_o_s), 0);
1303 
1304    	if (visible_ip_i == INADDR_ANY)
1305 	{
1306 		visible_ip_i = ourend_i.sin_addr.s_addr;
1307 		lookup_hostname(&ourend_i, visible_ip_i_s, sizeof(visible_ip_i_s), 0);
1308 	}
1309 
1310 	/* Log the facts about the connection.
1311 	*/
1312 	debug_msg(0, LOG_INFO, "%.64s -%.64s:%d-> %.64s:%d",
1313 			  from_host, user_name, ntohs(ourend.sin_port),
1314 			  to_host, ntohs(to_addr->sin_port));
1315 
1316 	/* Pass the data we read just now on to the server..
1317 	*/
1318    	if (is_server_connection)
1319 	{
1320 		junk = strlen(server_tag);
1321 		copy_once(sock, server_tag, 0, "tircproxy",
1322 				  server, ser_left, &ser_ln, "server",
1323 				  is_server_connection, 1, &junk);
1324 		copy_once(sock, headers, sizeof(headers), "client",
1325 				  server, ser_left, &ser_ln, "server",
1326 				  is_server_connection, 1, &read_len);
1327 		if (read_len <= 0) return 0;
1328 	}
1329 
1330 	/* Continue by passing data back and forth between the
1331 	** client and the server (or remote end of DCC).
1332 	*/
1333 	for (;;)
1334 	{
1335 		/* Construct a select read mask from both file descriptors.
1336 		*/
1337 		FD_ZERO(&read_fd);
1338 		FD_SET(sock, &read_fd);
1339 		FD_SET(server, &read_fd);
1340 		max_fd = FD_MAX(sock, server);
1341 
1342 		/* Allow 30 minutes for the loop to complete.
1343 		*/
1344 		signal(SIGALRM, alarm_signal);
1345 		alarm(30*MINUTE);
1346 	   	strcpy(alarm_in, "copy_loop: waiting");
1347 #ifdef TIRC_DEBUG
1348 	   	debug_msg(DEBUG_TRIVIA, LOG_DEBUG,"copy_loop: waiting");
1349 #endif
1350 		/* Wait for some data to be read.
1351 		*/
1352 	   	select_loop = 1;
1353 	   	while (select_loop)
1354 			if (select(max_fd + 1, &read_fd, NULL, NULL, NULL) < 0)
1355 			{
1356 				if (errno != EINTR) {
1357 #ifdef TIRC_DEBUG
1358 					debug_msg(DEBUG_BASIC, LOG_ERR,
1359 						  "select(): %.256s",
1360 						  strerror(errno));
1361 #endif
1362 				   	close(server);
1363 					return copied_bytes;
1364 				}
1365 			} else
1366 	    			select_loop = 0;
1367 
1368 	   	/* We aren't waiting anymore..
1369 		*/
1370 	   	strcpy(alarm_in, "copy_loop: copying");
1371 #ifdef TIRC_DEBUG
1372 	   	debug_msg(DEBUG_TRIVIA, LOG_DEBUG,"copy_loop: copying");
1373 #endif
1374 
1375 	   	if (is_server_connection)
1376 	     	{
1377 			/* Send the user a message, if requested by admin.
1378 			*/
1379 #ifdef BROADCAST_FILE
1380 		   	if (broadcast_flag) broadcast(sock, BROADCAST_FILE);
1381 #endif
1382 #ifdef IRC_MOTD_FILE
1383 			/* Send the user the MOTD.
1384 			*/
1385 			if ((!motd_sent) &&
1386 			    (motd_is_done) &&
1387 			    (is_server_connection))
1388 		     	{
1389 			   	broadcast(sock, IRC_MOTD_FILE);
1390 			   	motd_sent = 1;
1391 	  		}
1392 #endif
1393 		}
1394 
1395 		/* See if any data can be read from the client.
1396 		*/
1397 		if (FD_ISSET(sock, &read_fd))
1398 		{
1399 		   	read_len = 0;
1400 			copy_once(sock, headers, sizeof(headers), "client",
1401 				  server, ser_left, &ser_ln, "server",
1402 				  is_server_connection, 1,
1403 				  &read_len);
1404 			if (read_len < 0) return copied_bytes;
1405 		   	copied_bytes += read_len;
1406 		}
1407 
1408 		/* See if any data can be read from the server.
1409 		*/
1410 		if (FD_ISSET(server, &read_fd))
1411 		{
1412 		   	read_len = 0;
1413 			copy_once(server, headers, sizeof(headers), "server",
1414 				  sock, cli_left, &cli_ln, "client",
1415 				  is_server_connection, 0,
1416 				  &read_len);
1417 			if (read_len < 0) return copied_bytes;
1418 		   	copied_bytes += read_len;
1419 		}
1420 
1421 #ifdef QUIZ_MODE
1422 	   	/* Dump queued data meant for the client.
1423 		*/
1424 	   	if (use_quiz_mode && motd_is_done)
1425 			quiz_dump_lines(sock, QUIZ_C);
1426 
1427 	   	/* Dump queued data, stop quizzing if quiz mode is "flush".
1428 		*/
1429 	   	if ((use_quiz_mode == QUIZ_FLUSH) && (copied_bytes > 128))
1430 	     	{
1431 		   	quiz_dump_lines(server, QUIZ_S);
1432 		   	use_quiz_mode = QUIZ_OFF;
1433 		}
1434 #endif
1435 	}
1436 }
1437 
1438 
1439 /* This function handles a single copy cycle from one socket to another.
1440 ** If *read_len <= 0, then
1441 **	It reads at most rbufsize bytes from rsock, into rbuffer.
1442 ** If *read_len >= 0, then
1443 ** 	It writes the contents of rbuffer to wsock.
1444 **
1445 ** Writes are filtered if the is_server_connection is true.
1446 ** The function returns -1 or -2 on errors, or the number of read bytes on
1447 ** success.
1448 */
copy_once(int rsock,char * rbuffer,int rbufsize,char * rname,int wsock,char * wlbuffer,int * wlbufpos,char * wname,int is_server_connection,int r_is_client,int * read_len)1449 static int  copy_once(int rsock, char *rbuffer, int rbufsize, char *rname,
1450 		      int wsock, char *wlbuffer, int *wlbufpos, char *wname,
1451 		      int is_server_connection, int r_is_client,
1452 		      int *read_len)
1453 {
1454    	int rlen;
1455 
1456 #ifdef TIRC_DEBUG
1457 	debug_msg(DEBUG_TRIVIA, LOG_DEBUG,
1458 			  "Entering copy_once (reading %s, writing %s)",
1459 			  rname, wname);
1460 #endif
1461 
1462    	rlen = *read_len;
1463    	if (rlen <= 0) rlen = read(rsock, rbuffer, rbufsize - 1);
1464 
1465 	switch (rlen)
1466 	{
1467 	  case -1:
1468 #ifdef TIRC_DEBUG
1469 		debug_msg(DEBUG_BASIC,
1470 				  (errno == ECONNRESET ? LOG_DEBUG : LOG_WARNING),
1471 				  "read(%.32s) failed: %.256s", rname, strerror(errno));
1472 #endif
1473 		if (errno != EINTR)
1474 		{
1475 		   	close(wsock);
1476 			return -2;
1477 		}
1478 	   	return 0;
1479 	  case 0:
1480 #ifdef TIRC_DEBUG
1481 		debug_msg(DEBUG_TRIVIA, LOG_DEBUG, "EOF!");
1482 #endif
1483 		close(rsock);
1484 		close(wsock);
1485 		return -1;
1486 	  default:
1487 		if (*read_len >= 0)
1488 		{
1489 			if (is_server_connection)
1490 			{
1491 				if (!filtered_write(wsock, rbuffer, rlen,
1492 									wlbuffer, wlbufpos, r_is_client))
1493 				{
1494 #ifdef TIRC_DEBUG
1495 					debug_msg(DEBUG_BASIC, LOG_WARNING,
1496 							  "write(%.32s) failed: %.256s",
1497 							  wname, strerror(errno));
1498 #endif
1499 				   	close(rsock);
1500 				   	return 0;
1501 				}
1502 			}
1503 	   		else
1504 			{
1505 				while (write(wsock, rbuffer, rlen) < 0)
1506 				  if (errno != EINTR)
1507 				{
1508 #ifdef TIRC_DEBUG
1509 					debug_msg(DEBUG_BASIC, LOG_WARNING,
1510 							  "write(%.32s) failed: %.256s",
1511 							  wname, strerror(errno));
1512 #endif
1513 					close(rsock);
1514 					return 0;
1515 				}
1516 			}
1517 			break;
1518 		}
1519 	}
1520 #ifdef TIRC_DEBUG
1521 	debug_msg(DEBUG_TRIVIA, LOG_DEBUG,
1522 			  "Leaving copy_once (rlen = %d)", rlen);
1523 #endif
1524 
1525    	return (*read_len = rlen);
1526 }
1527 
1528 
1529 /* Line buffered write routine.. only dumps whole lines, and only
1530 ** after submitting them to the CTCP police.
1531 */
filtered_write(int to_sock,char * buff,int blen,char * leftover,int * llen,int isclient)1532 static int filtered_write(int to_sock, char *buff, int blen,
1533 			   	       	char *leftover, int *llen,
1534 			   		int isclient)
1535 {
1536    	char	*nl, *ol, *lp;
1537   	int	l,silent;
1538 
1539 #ifdef TIRC_DEBUG
1540 	debug_msg(DEBUG_TRIVIA, LOG_DEBUG, "Entering filtered_write");
1541 #endif
1542 
1543    	buff[blen] = '\0';	/* Null terminate buffer for strchr */
1544 
1545 	/* Break the input into lines, parse each one and send them one at
1546 	** a time to the client.
1547 	*/
1548    	nl = ol = buff;
1549    	lp = leftover + *llen;
1550    	while ((nl = strchr(ol,'\n')) != NULL)
1551 	{
1552 	   	/* nl points to the first '\n' in the input.
1553 		** ol points to the beginning of the unscanned input.
1554 	   	** lp points to the end of the contents of 'leftover'
1555 		**    which is the the fragment of a line we couldn't finish
1556 		**    processing last time.
1557 		*/
1558 
1559 	   	nl++;			/* Move nl past the '\n'		*/
1560 		l = nl-ol;		/* l = the length of this line		*/
1561 	   	if (l > 1500) l = 1500;	/* Arbitrary limits == bad!  FIXME!!		*/
1562 	   	memmove(lp, ol, l);	/* Append new line to leftover		*/
1563 	   	lp[l] = '\0';		/* Null terminate leftover		*/
1564 
1565 	   	/* Okay, now we have a complete line of data in the leftover
1566 		** buffer - scan it for interesting bits, and send it if it
1567 		** isn't deemed completely obscene. :)
1568 		*/
1569 	   	if ((silent = scan_line(leftover, isclient)) > 0)
1570 		{
1571 			while (write(to_sock, leftover,
1572 						 strlen(leftover)) < 0)
1573 			  if (errno != EINTR)
1574 			{
1575 #ifdef TIRC_DEBUG
1576 				debug_msg(DEBUG_BASIC, LOG_WARNING,
1577 						  "write(%s) failed: %.256s",
1578 						  isclient ? "client" : "server",
1579 						  strerror(errno));
1580 #endif
1581 				close(to_sock);
1582 				return 0;
1583 			}
1584 		}
1585 #ifdef TIRC_DEBUG
1586 			else if (silent >= 0)
1587 			  debug_msg(DEBUG_FEATURES, LOG_DEBUG,
1588 						"Squelched: %.256s", leftover);
1589 #endif
1590 
1591    		/* Maintain loop integrity..
1592 		*/
1593 		ol = nl;
1594 		lp = leftover;
1595 	}
1596    	/* Loop has terminated - if anything is left in ol, then it isn't
1597 	** a complete line we can scan, it's only a fragment.
1598 	**
1599 	** .. so we save it for next time, and return 1 for success.
1600 	*/
1601 	*llen = blen + (buff - ol);
1602 	memmove(leftover, ol, *llen);
1603 
1604 	return 1;
1605 }
1606 
1607 
1608 /* This function scans a single line of data for DCC constructs and other
1609 ** information we need to keep track of.  The line is rewritten if necissary.
1610 ** Returns 1 if the line is "okay for writing", 0 if it is to be suppressed,
1611 ** -1 if it is to be suppressed silently.
1612 */
1613 #define CTRL_A	('A'&31)
scan_line(char * line,int isclient)1614 static int scan_line(char *line, int isclient)
1615 {
1616 	char *done, *ctcp_begin, *ctcp_end, *p;
1617    	char replace[LENGTH_SERVERDATA * 2];
1618 
1619    	/* Sanity check..
1620 	*/
1621    	if (strlen(line) > LENGTH_SERVERDATA) {
1622 	   	debug_msg(0, LOG_ERR, "Input to scan_line() of illegal length - input not scanned!");
1623 	       	return(1);
1624 	}
1625 
1626    	/* Scan all CTCPs (it IS legal to embed more than one in the same,
1627 	** line, but most clients don't handle this correctly).
1628 	*/
1629    	done = line;
1630    	while (((ctcp_begin = strchr(done, CTRL_A)) != NULL) &&
1631 	       ((ctcp_end = strchr(ctcp_begin + 1, CTRL_A)) != NULL))
1632      	{
1633 	   	char ctcp_type[32];
1634 
1635 	   	strncpy(ctcp_type, ctcp_begin + 1, sizeof(ctcp_type));
1636 	   	ctcp_type[sizeof(ctcp_type) - 1] = '\0';
1637 	   	if ((p = strchr(ctcp_type, ' ')) != NULL) *p = '\0';
1638 
1639 	        /* It's a CTCP.. but is it DCC?
1640 		*/
1641 	   	if (!strcasecmp(ctcp_type, "DCC"))
1642 		{
1643 		   	/* Okay, it's DCC.. rewrite it!
1644 			*/
1645 		   	int		squelch = 0;
1646 		   	char		type[32];
1647 		   	char		arg_1[256];
1648 		   	char		*rest;
1649 		   	unsigned int	arg_2, arg_3, scanned;
1650 
1651 		   	*replace = *ctcp_begin = *ctcp_end = '\0';  /* Chop! */
1652 		   	ctcp_begin++;
1653 
1654 		   	if (sscanf(ctcp_begin, "%4s %31s %255s %u%u%n",
1655 			   	ctcp_type, type,
1656 			   	arg_1, &arg_2, &arg_3,
1657 			   	&scanned) >= 5)
1658 		     	{
1659 #ifdef TIRC_DEBUG
1660 			   	debug_msg(DEBUG_FEATURES, LOG_DEBUG,
1661 				       	"Caught: %.256s", ctcp_begin);
1662 #endif
1663 				rest = ctcp_begin + scanned;
1664 
1665        			   	if (!strcasecmp(type, "CHAT"))
1666 			     	{
1667        					if (!allow_dcc_chat)
1668 #ifdef DISALLOW_DCC_CHAT
1669 					        sprintf(replace,
1670 							DISALLOW_DCC_CHAT,
1671 							type, arg_1);
1672 #else
1673 						squelch = 1;
1674 #endif
1675        				}
1676        			   	else if (!strcasecmp(type, "SEND") ||
1677 				    	 !strcasecmp(type, "TSEND") ||
1678 					 !strcasecmp(type, "RESEND") ||
1679 					 !strcasecmp(type, "TRESEND"))
1680 			     	{
1681 			     		if (!allow_dcc_send)
1682 #ifdef DISALLOW_DCC_SEND
1683 					        sprintf(replace,
1684 							DISALLOW_DCC_SEND,
1685 							type, arg_1);
1686 #else
1687 						squelch = 1;
1688 #endif
1689 				   	else if (!dcc_mangle_filename(arg_1))
1690 #ifdef MANGLE_DCC_SEND
1691 					        sprintf(replace,
1692 							MANGLE_DCC_SEND,
1693 							type, arg_1);
1694 #else
1695 				 		squelch = 1;
1696 #endif
1697 			     	}
1698 			   	else if (!strcasecmp(type, "RESUME"))
1699 			     	{
1700 				        sprintf(replace,
1701 						"%cDCC %s %s %d %d%s%c",
1702 						CTRL_A,
1703 						type, arg_1,
1704 				   		dcc_resume(arg_2, 1),
1705 			   			arg_3, rest, CTRL_A);
1706        				}
1707        			   	else if (!strcasecmp(type, "ACCEPT"))
1708 			     	{
1709 				        sprintf(replace,
1710 						"%cDCC %s %s %d %d%s%c",
1711        						CTRL_A,
1712 						type, arg_1,
1713 				   		dcc_resume(arg_2, 0),
1714 				   		arg_3, rest, CTRL_A);
1715        				}
1716 			   	/* Insert new DCC protocols here :-)
1717 				*/
1718 				else if (!allow_dcc_unknown)
1719 #ifdef DISALLOW_DCC_SEND
1720 				        sprintf(replace,
1721 						DISALLOW_DCC_FUNK,
1722 						type, arg_1);
1723 #else
1724 			   		squelch = 1;
1725 #endif
1726 
1727        			   	if (!*replace && !squelch)
1728 				{
1729 				   	/* No replacement has been set, so
1730 					** proxy this connection.  :-)
1731 					*/
1732 				        sprintf(replace,
1733 						"%c%s %s %s %s%s%c",
1734        						CTRL_A, ctcp_type,
1735 						type, arg_1,
1736 					    proxy_dcc(arg_2, arg_3, isclient),
1737        						rest, CTRL_A);
1738 				}
1739 			}
1740 
1741 		   	/* Alternate (!= DCC) protocols go here.. */
1742 
1743 		   	/* Are we changing anything?
1744 			*/
1745 		   	ctcp_begin--;
1746 		   	if (*replace)
1747 		     	{
1748 #ifdef TIRC_DEBUG
1749 			   	debug_msg(DEBUG_FEATURES, LOG_DEBUG,
1750 					  "Sent: %.256s", replace);
1751 #endif
1752 			   	done = ctcp_begin + strlen(replace); /* Mark */
1753 			   	strcat(replace, ctcp_end + 1);
1754 			   	strcpy(ctcp_begin, replace);	  /* Rewrite */
1755 			}
1756 		   	else
1757 		     	{
1758 			   	*ctcp_begin = *ctcp_end = CTRL_A;  /* Unchop */
1759 			   	done = ctcp_end + 1;		    /* Mark */
1760 
1761 			   	if (squelch)
1762 			     		return(0);
1763 			}
1764 		} /* is DCC */
1765 	   	else if ((use_anonymity) &&
1766 			 (isclient) &&
1767 			 ((!strcasecmp(ctcp_type, "VERSION")) ||
1768 			  (!strcasecmp(ctcp_type, "FINGER")) ||
1769 			  (!strcasecmp(ctcp_type, "USERINFO")) ||
1770 			  (!strcasecmp(ctcp_type, "CLIENTINFO"))) &&
1771 			  (!strncasecmp(line, "NOTICE", 6)))
1772      		{
1773 		   	strcpy(replace, CTCP_NOT_ALLOWED);
1774 		   	done = ctcp_begin + strlen(replace) + 2; /* Mark */
1775 		   	strcat(replace, ctcp_end);
1776 		   	strcpy(ctcp_begin + 1, replace);       /* Rewrite */
1777 		}
1778 	   	else if (isclient)
1779 	     	{
1780 		   	/* Squelch other outgoing CTCPs containing the
1781 			** client's IP address.
1782 			*/
1783 		   	if (strstr(ctcp_begin, clients_ip_s) != NULL)
1784 		     		return (0);
1785 	     		done = ctcp_end + 1;
1786 		}
1787 	   	else
1788 	     		done = ctcp_end + 1;
1789      	}
1790 
1791 	/* Scan server input for the client's nickname.
1792 	*/
1793    	if (!isclient)
1794      	{
1795 		char type[128];
1796 	   	char arg[32];
1797 		char nuh[512];
1798 
1799        	   	if (sscanf(line, ":%511s %127s %31s", nuh, type, arg) == 3)
1800 		{
1801 			if ((isdigit(*type) ||
1802 			    (!strcasecmp(type, "PRIVMSG"))) &&
1803 			    ((*arg != '&') && (*arg != '#') &&
1804 			     (*arg != '%') &&
1805 			     (*arg != '!') && (*arg != '*')))
1806 			{
1807 #ifdef NICK_LOG
1808 			   	if (use_nick_log &&
1809 				    strcasecmp(user_nick, arg))
1810 			     		debug_msg(0, LOG_INFO, "Nick: %.256s", arg);
1811 #endif
1812 			   	strncpy(user_nick, arg, sizeof(user_nick));
1813 			   	user_nick[sizeof(user_nick) - 1] = '\0';
1814 			}
1815 		   	if ((!motd_is_done) &&
1816 			    ((!strcasecmp(type,"376")) ||
1817 			     (!strcasecmp(type,"421"))))
1818 		     		motd_is_done = 1;
1819    		}
1820 	   	/* The server shouldn't start PINGing us until well
1821 		** after the end of the MOTD..
1822 		*/
1823 	   	if ((!motd_is_done) && (!strncasecmp(line,"PING",4)))
1824 	     		motd_is_done = 1;
1825      	}
1826    	else if (use_anonymity) 	/* Data is from client, anonymize */
1827      	{
1828 	   	if (!strncasecmp(line, "NOTICE", 6))
1829 	     	{
1830 		   	if (strstr(line, clients_ip_s) != NULL)
1831 		     		return (0);
1832 		}
1833 	   	else if (!strncasecmp(line, "USER", 4))
1834 	     	{
1835 	   		int cip = ANON_USERID;
1836 	   		sprintf(line,
1837 				"USER t%x anon anon :%s\n",
1838 				cip, ANON_IRCNAME);
1839 		}
1840 	}
1841    	else if (!strncasecmp(line, "NOTICE", 6))	/* Fix mIRC junk */
1842      	{
1843 	   	char *p;
1844 	   	while ((p = strstr(line, clients_ip_s)) != NULL)
1845 	     	{
1846 		   	*p = '\0';
1847 		   	strcpy(replace, p+strlen(clients_ip_s));
1848 		   	strcat(line, visible_ip_o_s);
1849 		   	strcat(line, replace);
1850 	     	}
1851 	}
1852 
1853    	/* Other spying could be done here .. */
1854 
1855 #ifdef QUIZ_MODE
1856    	if (use_quiz_mode) {
1857 	   	if ((isclient) && (use_quiz_mode <= QUIZ_FLUSH))
1858 	     	{
1859 		   	char cmd[32];
1860 		   	char rest[512], out[512], *r;
1861 		   	int what, retv, fuid;
1862 
1863 		   	what = 0;
1864 			if (sscanf(line, "%31s %511s", cmd, rest) == 2)
1865 		     	{
1866 		   		if (!strcasecmp(cmd, "NICK"))	 what = 1;
1867 		   	   else if (!strcasecmp(cmd, "USER"))	 what = 2;
1868 		   	   else if (!strcasecmp(cmd, "PASS"))	 what = 3;
1869 		   	   else if (!strcasecmp(cmd, "PRIVMSG")) what = 4;
1870 			   else if (!strncasecmp(line, server_tag, 6))
1871 			     					 what = 2;
1872 
1873 			   	r = line+strlen(cmd)+1;
1874 		   		if (*r == ':') r++;
1875 				strncpy(rest, r, sizeof(rest)-1);
1876 				rest[511] = '\0' ;
1877 			   	if ((r = strchr(rest,'\n')) != NULL) *r = '\0';
1878 			}
1879 		   	else if	(!strncasecmp(line, server_tag, 6)) what = 2;
1880 
1881 		   	r = rest;
1882 		   	retv = -1;
1883 		   	switch (what)
1884 		     	{
1885 					/* Users get fake nicks until after
1886 					** authentication (anti-nick-kill).
1887 					*/
1888 			 case 1:	quiz_delay_line(line, QUIZ_S);
1889 			   		fuid = getpid() * visible_ip_o;
1890 			   		sprintf(user_nick, "}%x", fuid);
1891 			   		sprintf(line, "NICK :%s\n", user_nick);
1892 			   		sprintf(out, ":%.32s %.256s", r, line);
1893 					quiz_delay_line(out, QUIZ_C);
1894 			   		quiz_greet();
1895 			   		retv = 1;
1896 			   		break;
1897 
1898 					/* Allow the USER command.
1899 			     		*/
1900 			 case 2:	retv = 1;
1901 			   		strcat(line,"#PiNG#\n");
1902 					break;
1903 
1904 				 	/* Check the users' responses.
1905 					*/
1906 			 case 4:	if ((r = strchr(rest,' ')) != NULL)
1907 			     		{
1908 					   	*r++ = '\0';
1909 					   	if (*r == ':') r++;
1910 					}
1911 		   			if (strcasecmp(rest, QUIZ_NICK))
1912 		     			{
1913 					   	quiz_delay_line(line, QUIZ_S);
1914 					   	break;
1915 			    		}
1916 			 case 3:	quiz_check_auth(r);
1917 		   			break;
1918 			 default:	quiz_delay_line(line, QUIZ_S);
1919 			   		break;
1920 			}
1921 
1922 			return(retv);
1923 		}
1924 	}
1925 #endif
1926 	return(1);
1927 }
1928 
1929 
1930 /* Mangle the given filename.  Returns 1 if the filename
1931 ** is okay, 0 if not.
1932 */
dcc_mangle_filename(char * filename)1933 static int dcc_mangle_filename(char *filename)
1934 {
1935    	struct dcc_mangle_struct *dmp;
1936 
1937    	/* Check the compiled-in rules first:
1938 	*/
1939 	dmp = dcc_mangle;
1940   	while (use_dcc_mangling &&
1941 	       (dmp->offered != NULL))
1942      	{
1943 	   	if (!strcasecmp(filename, dmp->offered))
1944      		{
1945      			if (dmp->replace != NULL)
1946 				strcpy(filename, dmp->replace);
1947 			else
1948 		     		return(0);
1949 		}
1950    		dmp++;
1951 	}
1952 
1953 #ifdef TCP_WRAPPERS
1954 	/* Check if the offered file is on the
1955 	** local blacklist.
1956 	*/
1957 	if (use_tcp_wrappers)
1958      	{
1959 		if (!hosts_ctl("tircproxy_dcc_files",
1960 		   	       "", "", filename))
1961 	     		return(0);
1962 	}
1963 #endif
1964 	return(1);
1965 }
1966 
1967 
1968 /* Looks up valid port numbers for proxying DCC RESUME requests.
1969 ** Set resume to 0 on "DCC RESUME", 1 on "DCC ACCEPT".
1970 */
dcc_resume(int destport,int resume)1971 static int dcc_resume(int destport, int resume)
1972 {
1973    	int i;
1974 
1975    	for (i = 0; i < MAX_DCC_SESSIONS; i++)
1976      	{
1977 	   	if ((resume) && (dcc_proxied_port[i] == destport))
1978 	     	{
1979 		   	return(dcc_original_port[i]);
1980 		}
1981 	   	else if ((!resume) && (dcc_original_port[i] == destport))
1982 	     	{
1983 		   	return(dcc_proxied_port[i]);
1984 		}
1985 	}
1986 	return (0);
1987 }
1988 
1989 
1990 /* This prepares to proxy a DCC session.  Ut returns a pointer
1991 ** to a string containing the "<ip> <port>" reply to send to the
1992 ** client.
1993 */
proxy_dcc(int destaddr,int destport,int incoming)1994 static char *proxy_dcc(int destaddr, int destport, int incoming)
1995 {
1996    	static char				retvalue[128];
1997 	int					listen_sock;
1998 	int					sock;
1999    	ipaddr_t				vip;
2000 	struct sockaddr_in			addr;
2001 	struct sockaddr_in			to_addr;
2002 	int					len;
2003 
2004 	/* Mangle DCC offers below port 1024.
2005 	*/
2006    	if (destport < 1024)
2007      	{
2008 	   	strcpy(retvalue,"junk junk");
2009 	   	return retvalue;
2010 	}
2011 
2012 #ifdef MIRC_DCC_KLUDGE
2013    	if (incoming && use_mirc_dcc_kludge) destaddr = ntohl(clients_ip);
2014 #endif
2015 
2016 #ifdef TCP_WRAPPERS
2017      	if (use_tcp_wrappers)
2018      	{
2019 		char host_ip[64], host_name[64];
2020 	   	struct sockaddr_in addr;
2021 	   	int okay = 1;
2022 
2023    		/* Lookup an ASCII representation of the host's IP address,
2024 		** and attempt to look up it's FQDN as well (DNS).
2025        		*/
2026 		addr.sin_addr.s_addr = htonl(destaddr);
2027        		lookup_hostname(&addr, host_ip, sizeof(host_ip), 0);
2028        		lookup_hostname(&addr, host_name, sizeof(host_name), 1);
2029 
2030    		/*  Check if the calling host is allowed to initiate DCC.
2031 		*/
2032 	   	if (!hosts_ctl((incoming) ? "tircproxy_dcc_out" :
2033 			       		    "tircproxy_dcc_in",
2034 			       host_name, host_ip,
2035 			       (incoming) ? "" : user_name))
2036 	     	{
2037 	     		okay = 0;
2038 		}
2039 
2040 	   	if (clients_ip != htonl(destaddr))
2041 	     	{
2042 			addr.sin_addr.s_addr = clients_ip;
2043 	       		lookup_hostname(&addr, host_ip, sizeof(host_ip), 0);
2044 	       		lookup_hostname(&addr, host_name, sizeof(host_name), 1);
2045 
2046 	   		/*  Check if the client is allowed to use DCC.
2047 			*/
2048 	       		if (!hosts_ctl("tircproxy_dcc_in",
2049 				       host_name, host_ip,
2050 				       user_name))
2051 		     	{
2052 		     		okay = 0;
2053 			}
2054 		}
2055 
2056 	   	if (!okay)
2057 	     	{
2058 		   	debug_msg(0, LOG_INFO,
2059 			       	"Dropped illegal DCC from: %.128s (client %.32s@%.96s)",
2060 			       		host_ip, user_name,
2061 			       		inet_ntoa(addr.sin_addr));
2062 		   	strcpy(retvalue,"junk junk");
2063 		   	return(retvalue);
2064 		}
2065 	}
2066 #endif
2067 
2068    	/* Choose a DCC port at random, to make hijacking harder.
2069 	** 	(re: BUGTRAQ, 1998, December 22 & 23)
2070 	*/
2071 	len = 10;
2072 	while ((listen_sock = bind_to_port((incoming) ? visible_ip_o : visible_ip_i,
2073 					   ((rand() + getpid()) % PPOOL) + 1025,
2074 					   1, DEBUG_TRIVIA)) < 0)
2075      	{
2076 	   	if (--len < 1) {
2077 		   	debug_msg(0, LOG_ERR, "Failed to bind to port, dropping DCC!");
2078 
2079 		   	strcpy(retvalue, "ack, pthpht!");
2080 		   	return(retvalue);
2081 		}
2082 	}
2083 
2084 	/* call cleanup func on SIGCHLD
2085 	*/
2086 	signal(SIGCHLD, chld_signal);
2087 
2088    	if (fork())
2089      	{
2090 	   	int i,n;
2091 
2092        		len = sizeof(to_addr);
2093 		if (getsockname(listen_sock, (struct sockaddr *)&to_addr, &len) < 0)
2094 		{
2095 			debug_msg(0, LOG_ERR, "getsockname(): %.256s", strerror(errno));
2096 		   	*retvalue = '\0';
2097 			return(retvalue);
2098 		}
2099 	       	/* Close the socket as the child does the handling.
2100 	       	*/
2101 	       	close(listen_sock);
2102 
2103 	   	vip = to_addr.sin_addr.s_addr;
2104 
2105 	   	/* Record the port info for this connection.
2106 		*/
2107 	   	for (n = i = 0; i < MAX_DCC_SESSIONS; i++)
2108 	     		if (dcc_session_time[i] < dcc_session_time[n]) n = i;
2109 
2110 	   	dcc_session_time[n] = time(NULL);
2111 	   	dcc_original_port[n] = destport;
2112 	   	dcc_proxied_port[n] = ntohs(to_addr.sin_port);
2113 
2114 #ifdef HAVE_LINUX
2115 	   	sprintf(retvalue,"%lu %u",
2116 			(unsigned long int) ntohl(vip), ntohs(to_addr.sin_port));
2117 #else
2118 	   	sprintf(retvalue,"%u %u",
2119 			(unsigned int) ntohl(vip), ntohs(to_addr.sin_port));
2120 #endif
2121 	   	return(retvalue);
2122  	}
2123 
2124    	/* Give people five minutes to accept the call..
2125 	*/
2126 	signal(SIGALRM, alarm_signal);
2127    	alarm(5*MINUTE);
2128    	strcpy(alarm_in,"proxy_dcc: accept");
2129 
2130    	/* No silly broadcasts shall mess up our DCC stuff!
2131 	*/
2132        	signal(SIGHUP, SIG_IGN);
2133 
2134        	/* Accept an incoming connection.
2135        	*/
2136        	len = sizeof(addr);
2137        	if ((sock = accept(listen_sock, (struct sockaddr *)&addr, &len)) < 0)
2138 	{
2139        		/* Connection resets are common enough to log them as debug only.
2140        		*/
2141        		debug_msg(0, (errno == ECONNRESET ? LOG_DEBUG : LOG_ERR), "accept(): %.256s", strerror(errno));
2142 	   	exit (0);
2143        	}
2144    	close(listen_sock);
2145 
2146 	/* Ok, here we go!
2147 	*/
2148    	memset(&to_addr, '\0', sizeof(to_addr));
2149 	to_addr.sin_family = AF_INET;
2150 	to_addr.sin_port = htons(destport);
2151 	to_addr.sin_addr.s_addr = htonl(destaddr);
2152 
2153    	/*  Make sure at least *one* end of the connection
2154 	**  is the original client.
2155 	*/
2156 	if ((to_addr.sin_addr.s_addr != clients_ip) &&
2157 	    (addr.sin_addr.s_addr != clients_ip))
2158      	{
2159 	   	debug_msg(0, LOG_WARNING, "Abuse: illegal DCC request %.128s <-> %.128s !",
2160 		       	       	inet_ntoa(to_addr.sin_addr),
2161 		       		inet_ntoa(addr.sin_addr));
2162      		exit(0);
2163 	}
2164 
2165  	debug_msg(0, LOG_DEBUG,
2166 	       	"Copied %d bytes, exiting (DCC).",
2167 	   	copy_loop(sock, &addr, &to_addr, 0));
2168 
2169 #ifdef CDIR_IDENT
2170    	if (use_cdir)
2171      		cleanup_identd();
2172 #endif
2173        	close(sock);
2174        	closelog();
2175      	exit(0);
2176 }
2177 
2178 
2179 /* Read username from disk or shared memory, if possible.
2180 */
get_user_name(struct sockaddr_in * addr)2181 static void get_user_name(struct sockaddr_in *addr)
2182 {
2183    	int	tries = 0;
2184 #ifdef USE_UDB
2185 	struct udb_ip_user buf;
2186 
2187 	/* People neither using the CDIR stuff nor running as root probably
2188 	 * couldn't care less about ident problems.
2189 	 */
2190 	if (!use_cdir && getuid()) tries = 10;
2191 
2192    	/* Be stubborn, to decrease the chance of race conditions.
2193 	 */
2194 	while (!udb_ip_get(&(addr->sin_addr), &buf))
2195 	{
2196 		if (tries > 3)
2197 		{
2198 			debug_msg(0, LOG_WARNING,
2199 					  "Address not in UDB table, ident response will be wrong!");
2200 			return;
2201 		}
2202 		else
2203 		{
2204 			tries++;
2205 			sleep(1);
2206 		}
2207 	}
2208 
2209 #ifdef TIRC_DEBUG
2210 	debug_msg(DEBUG_TRIVIA, LOG_DEBUG, "Got username: %.256s", buf.username);
2211 #endif
2212 
2213 	strncpy(user_name, buf.username, MAXLOGNAME);
2214    	user_name[MAXLOGNAME-1] = '\0';
2215 	return;
2216 
2217 #endif /* USE_UDB */
2218 #ifdef IP_TO_UID_PREFIX /* not USE_UDB */
2219    	int	 fd;
2220    	char ipfile[PATH_MAX];
2221    	char *cp;
2222 
2223 	/* People neither using the CDIR stuff nor running as root probably
2224 	 * couldn't care less about ident problems.
2225 	 */
2226 #ifdef CDIR_IDENT
2227 	if (!use_cdir && getuid()) tries = 10;
2228 #endif
2229 
2230 	/* FIXME: dangerous sprintfs */
2231 #ifdef CDIR
2232 	if (use_cdir)
2233 # ifdef HAVE_SNPRINTF
2234 	  snprintf(ipfile, sizeof(ipfile),
2235 # else
2236 	  sprintf(ipfile,
2237 # endif
2238 			  "%s%s-%s", CDIR, CDIR_MAP,
2239 			  inet_ntoa(addr->sin_addr));
2240     else
2241 #endif
2242 # ifdef HAVE_SNPRINTF
2243 	  snprintf(ipfile, sizeof(ipfile),
2244 # else
2245 	  sprintf(ipfile,
2246 # endif
2247 			  "%s%s", IP_TO_UID_PREFIX,
2248 			  inet_ntoa(addr->sin_addr));
2249 
2250    	/*  Repeat until we lose the ident race.. :-)
2251 	 */
2252 	while ((fd = open(ipfile,O_RDONLY)) == -1)
2253 	{
2254 		if (tries > 5) {
2255 			debug_msg(0, LOG_WARNING,
2256 					  "No %.256s file found, ident response will be wrong!",
2257 					  ipfile);
2258 		   	return;
2259 		}
2260 		else
2261 		{
2262 			sleep(1);
2263 		}
2264 	   	tries++;
2265 	}
2266 
2267    	user_name[0] = user_name[MAXLOGNAME-1] = '\0';
2268    	read(fd, user_name, MAXLOGNAME-1);
2269    	close(fd);
2270 
2271    	if ((cp = strchr(user_name,'\n'))) *cp = '\0';
2272 	return;
2273 
2274 #endif /* IP_TO_UID_PREFIX */
2275 }
2276 
2277 /* Change uid & gid!
2278 */
change_uid(void)2279 static void change_uid(void)
2280 {
2281 #if (defined IP_TO_UID_PREFIX || defined USE_UDB)
2282    	struct passwd *pw;
2283 
2284    	/* We aren't running as root, so there's nothing more we can do..
2285 	*/
2286    	if (getuid()) return;
2287 
2288 	if ((pw = getpwnam(user_name)) == NULL)
2289 	{
2290 		debug_msg(0, LOG_WARNING,
2291 				  "Invalid user: %.32s, didn't changed UID/GID.",
2292 				  user_name);
2293 # ifdef PARANOID
2294 	   	if (use_paranoid) exit(0);
2295 # endif
2296 	 	return;
2297 	}
2298 
2299  	/* Change ids..
2300 	*/
2301    	setgid(pw->pw_gid);
2302    	setuid(pw->pw_uid);
2303 
2304 	/* Start a new session and group.
2305 	*/
2306 	setsid();
2307 # ifdef HAVE_LINUX
2308    	setpgrp();
2309 # endif
2310 #endif /* IP_TO_UID_PREFIX */
2311    	return;
2312 }
2313 
2314 
2315 /* Tell the ident server which user this connection really belongs to.
2316 */
2317 #ifdef CDIR
tell_identd(struct sockaddr_in * us,struct sockaddr_in * them)2318 static void tell_identd(struct sockaddr_in *us, struct sockaddr_in *them)
2319 {
2320    	char fakeid[64], *u;
2321 # ifndef USE_UDB
2322    	int fd;
2323    	*user_ident_file = '\0';
2324 
2325 	sprintf(user_ident_file,
2326 			"%s%s:%d-%s:%d", CDIR, CDIR_IDENT,
2327 			ntohs(us->sin_port),
2328 			inet_ntoa(them->sin_addr),
2329 			ntohs(them->sin_port));
2330 
2331    	if ((fd = creat(user_ident_file, S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH)) == -1)
2332 	{
2333 		debug_msg(0, LOG_WARNING,
2334 				  "Unable to create %s, ident response will be wrong!",
2335 				  user_ident_file);
2336 	   	*user_ident_file = '\0';
2337 	   	return;
2338 	}
2339 # endif
2340 
2341 	if ((use_anonymity) || (!*user_name))
2342 	{
2343 	   	int cip = ANON_USERID;
2344 
2345 	   	sprintf(fakeid, "t%x", cip);
2346 		debug_msg(0, LOG_INFO, "Anonymized connection as %s", fakeid);
2347 
2348 		u = fakeid;
2349 	}
2350 	else
2351 	  u = user_name;
2352 
2353 # ifdef USE_UDB
2354 	memset(&conn, 0, sizeof(conn));
2355 	conn.from.sin_family = us->sin_family;
2356 	conn.from.sin_addr = us->sin_addr;
2357 	conn.from.sin_port = us->sin_port;
2358 	conn.to.sin_family = them->sin_family;
2359 	conn.to.sin_addr = them->sin_addr;
2360 	conn.to.sin_port = them->sin_port;
2361 
2362 	udb_conn_record(&conn, u, "", UDB_OVERWRITE_LRU, UDB_NOW);
2363 
2364 # else
2365    	if (write(fd, u, strlen(u)) < 0)
2366 	  debug_msg(0, LOG_WARNING,
2367 		       	"Unable to write to %s, ident response will be wrong!",
2368 		       	user_ident_file);
2369 
2370    	close(fd);
2371 # endif
2372 }
2373 
2374 /* Cleanup ..
2375 */
cleanup_identd(void)2376 static void cleanup_identd(void)
2377 {
2378 # ifdef USE_UDB
2379 	udb_conn_delete(&conn);
2380 # else
2381    	if (*user_ident_file)
2382      		unlink(user_ident_file);
2383 # endif
2384 }
2385 #endif /* CDIR */
2386 
2387 
2388 /* Broadcast a message from sysadmin to proxy user.. It's the
2389 ** sysadmin's problem to format the file so the client will understand
2390 ** the message!
2391 */
broadcast(int sock,const char * filename)2392 static void broadcast(int sock, const char *filename)
2393 {
2394    	int		fd,i;
2395    	char 		buff[2048], *p, *np;
2396 
2397 #ifdef HAVE_LINUX
2398    	/* man signal:
2399 	**
2400 	** 	Unlike BSD systems, signals under Linux are reset to their
2401 	** 	default values when raised.
2402 	*/
2403        	signal(SIGHUP, hup_signal);
2404 #endif
2405       	broadcast_flag = 0;
2406 
2407    	if ((fd = open(filename,O_RDONLY)) == -1) return;
2408   	debug_msg(0, LOG_DEBUG, "Sending broadcast from: %.256s",filename);
2409 
2410    	while ((i = read(fd, buff, 2047)) > 0)
2411      	{
2412 	   	buff[2047] = '\0';
2413 	   	np = p = buff;
2414 
2415 	   	while ((np = strstr(p, "$N$")) != NULL)
2416 	     	{
2417 		   	if (write(sock, p, np-p) < 0)
2418 		     		debug_msg(0, LOG_WARNING, "Error writing to socket!");
2419 		   	p = np+3;
2420 		   	write(sock, user_nick, strlen(user_nick));
2421 		}
2422 	   	if (write(sock, p, (buff+i)-p) < 0)
2423 	     		debug_msg(0, LOG_WARNING, "Error writing to socket!");
2424 	}
2425    	close(fd);
2426 }
2427 
2428 
2429 /* Catch alarm signals and exit.
2430 */
alarm_signal(int sig)2431 static void alarm_signal(int sig)
2432 {
2433 	debug_msg(0, LOG_DEBUG, "Timeout in %.256s, exiting.", alarm_in);
2434 #ifdef CDIR_IDENT
2435    	if (use_cdir)
2436      		cleanup_identd();
2437 #endif
2438 	exit(1);
2439 }
2440 
2441 
2442 /* Catch HUP signals and set broadcast flag.
2443 */
hup_signal(int sig)2444 static void hup_signal(int sig)
2445 {
2446 	debug_msg(0, LOG_DEBUG, "HUP signal caught - broadcasting!");
2447    	broadcast_flag = 1;
2448 }
2449 
2450 
2451 /* SIGCHLD handler (reap zombies)
2452 */
chld_signal(sig)2453 static void chld_signal (sig)
2454 {
2455 	int status;
2456 	while (waitpid(-1,&status,WNOHANG) > 0);
2457 #ifdef HAVE_LINUX
2458 
2459    	/* Reset the signal handler.
2460 	*/
2461 	signal(SIGCHLD,chld_signal);
2462 #endif
2463 }
2464 
2465 /* Debug message handler
2466 */
debug_msg(int lev,int pri,const char * format,...)2467 static void debug_msg(int lev, int pri, const char *format, ...) {
2468 	va_list ap;
2469    	char msg[512];
2470 
2471    	if (lev > debug_level) return;
2472 
2473      	va_start(ap,format);
2474 #if HAVE_VSNPRINTF
2475 	vsnprintf(msg, 511, format, ap);
2476 #else
2477 # if HAVE_VPRINTF
2478 #  warning Using vsprintf instead of vsnprintf!
2479 	vsprintf(msg, format, ap);
2480 # else
2481 #  error I need vsprintf or vsnprintf!
2482 # endif
2483 #endif
2484 
2485    	if ((use_syslog) && (debug_level < DEBUG_NOFORK))
2486      		syslog(pri, "%s", msg);
2487 	else 	fprintf(stderr,"[%d]\t%s\n", getpid(), msg);
2488 
2489    	va_end(ap);
2490 }
2491 
2492 /* ************************************************************************* */
2493 
2494 #ifdef QUIZ_MODE
2495 
2496 # define QSTR(b)	(b+sizeof(char *))
2497 # define QPTR(b)	*((char **) b)
2498 
2499 /* Save a line that was destined for output for later..
2500 */
2501 int quiz_delayed = 0;
quiz_delay_line(char * line,char ** first,char *** bl)2502 static void quiz_delay_line(char *line, char **first, char ***bl)
2503 {
2504    	char *buf;
2505 	int linelen;
2506 
2507 	quiz_delayed += linelen = strlen(line);
2508 
2509 	if (quiz_delayed > QUIZ_MEMORY_HOG) exit(1);
2510 
2511 	if (*bl == NULL) *bl = first;
2512 
2513    	**bl = buf = malloc(sizeof(char *)+linelen+1);
2514 	strcpy(QSTR(buf), line);
2515 
2516 	QPTR(buf) = NULL;
2517 	*bl = &QPTR(buf);
2518 
2519 #ifdef TIRC_DEBUG
2520 	debug_msg(DEBUG_TRIVIA, LOG_DEBUG, "Buffered: %.256s", line);
2521 #endif
2522 }
2523 
2524 /* Print a line that was destined for output for later..
2525 */
quiz_dump_lines(int sock,char ** first,char *** bl)2526 static void quiz_dump_lines(int sock, char **first, char ***bl)
2527 {
2528    	char *p;
2529 
2530 	if (*first == NULL) return;
2531 
2532 	do {
2533 		while (write(sock, QSTR(*first),
2534 			      strlen(QSTR(*first))) < 0)
2535 			if (errno != EINTR)
2536 		{
2537 #ifdef TIRC_DEBUG
2538 			debug_msg(DEBUG_BASIC, LOG_WARNING,
2539 			       "write(%s) failed in quiz_dump_lines: %.128s",
2540 			       strerror(errno));
2541 #endif
2542 			return;
2543 		}
2544 #ifdef TIRC_DEBUG
2545 		debug_msg(DEBUG_TRIVIA, LOG_DEBUG,
2546 			  "Flushed: %.256s", QSTR(*first));
2547 #endif
2548 		p = QPTR(*first);
2549 		free(*first);
2550 		*first = p;
2551 	} while (*first != NULL);
2552 
2553    	*bl = first;
2554 }
2555 
2556 /* Check the username%password supplied by the user.
2557 */
2558 int quiz_passwd_checks = 0;
quiz_check_auth(char * pass)2559 static void quiz_check_auth(char *pass)
2560 {
2561 	if (quiz_passwd_checks++ > 3) exit(1);
2562 
2563    	if (use_unix_passwd)
2564      	{
2565 	  	char *u, *p, *n, salt[4];
2566 	   	struct passwd *pw;
2567 
2568 		if (((p = strchr(pass,'%')) != NULL) ||
2569 		    ((p = strchr(pass,' ')) != NULL))
2570 	     	{
2571 		   	u = pass;
2572 		   	*p++ = '\0';
2573 		}
2574 	   	else if (*user_name)
2575 	     	{
2576 		   	u = user_name;
2577 			p = pass;
2578 	  	}
2579 	   	else
2580 	     	{
2581 		   	quiz_msg(QUIZ_PASSWD_BAD);
2582 		   	return;
2583 	     	}
2584 
2585 		if ((n = strchr(p,'\n')) != NULL) *n = '\0';
2586 
2587 		if ((pw = getpwnam(u)) != NULL)
2588 	     	{
2589 		       	salt[0] = (pw->pw_passwd)[0];
2590 		       	salt[1] = (pw->pw_passwd)[1];
2591 		   	salt[2] = '\0';
2592 		   	if (!strcmp(pw->pw_passwd, crypt(p,salt)))
2593 		     	{
2594 				quiz_msg(QUIZ_PASSWD_OK);
2595 			   	use_quiz_mode = QUIZ_FLUSH;
2596 			   	bzero(p,strlen(p));
2597 			   	return;
2598 			}
2599 		}
2600 
2601 #ifdef TIRC_DEBUG
2602 		debug_msg(DEBUG_FEATURES, LOG_AUTH,
2603 			  "Incorrect password given for %s", u);
2604 #endif
2605 	   	bzero(p,strlen(p));
2606 	   	sleep(quiz_passwd_checks*2);
2607 		quiz_msg(QUIZ_PASSWD_BAD);
2608 	}
2609  	else /* use_unix_passwd */
2610      	{
2611 		char *b, *p, buf[512], ok;
2612 
2613 		strcpy(buf,quiz);
2614 	   	b = p = buf;
2615 	   	ok = 0;
2616 
2617 		while ((p = strchr(p,':')) != NULL)
2618 	     	{
2619 		   	*p++ = '\0';
2620 		   	if (!strcasecmp(pass,b)) ok = 1;
2621 			b = p;
2622 		}
2623 	   	if (!strcasecmp(pass,b)) ok = 1;
2624 
2625 		if (ok)
2626 		{
2627 			quiz_msg(QUIZ_PASSWD_OK);
2628 			use_quiz_mode = QUIZ_FLUSH;
2629 		}
2630 	   	else
2631 	     	{
2632 #ifdef TIRC_DEBUG
2633 			debug_msg(DEBUG_TRIVIA, LOG_DEBUG,
2634 				  "Incorrect quiz response: %s", pass);
2635 #endif
2636 			quiz_msg(QUIZ_ANSWER_BAD);
2637 		}
2638 
2639      	} /* else */
2640 }
2641 
2642 /* Send the user a message..
2643 */
quiz_msg(char * message)2644 static void quiz_msg(char *message)
2645 {
2646    	char out[512];
2647 
2648    	sprintf(out,":%.32s!irc@proxy PRIVMSG %.32s :%.256s\n",
2649 			QUIZ_NICK, user_nick, message);
2650 
2651    	quiz_delay_line(out, QUIZ_C);
2652 }
2653 
2654 /* Greet the user when he connects..
2655 */
quiz_greet(void)2656 static void quiz_greet(void)
2657 {
2658    	FILE  *fd;
2659    	int   i, r;
2660    	char  question[512], buff[512], *p;
2661 
2662 	if (use_unix_passwd)
2663 	{
2664 		quiz_msg(QUIZ_PASSWD_WAIT);
2665 	   	return;
2666 	}
2667 
2668    	/* Not using /etc/passwd, select a question from the quizfile */
2669 
2670    	srand(time((time_t) NULL));
2671 
2672    	if ((fd = fopen(quizfile,"r")) == NULL)
2673 	{
2674 	  	debug_msg(0, LOG_DEBUG,
2675 				  "Error (%.128s) reading quiz-file: %.128s",
2676 				  strerror(errno), quizfile);
2677 	   	quiz_msg("Error opening quiz file.  Notify the proxy administrator.");
2678 	   	return;
2679 	}
2680 
2681    	r = 0;
2682    	while (fgets(buff, 512, fd) != NULL)
2683 	  if (*buff == '!')
2684 		quiz_msg(buff+1);
2685 	  else
2686 	    if (*buff != '#')
2687 	{
2688 		i = rand();
2689 		if ((i > r) || (!r))
2690 		{
2691 			r = i;
2692 			strcpy(question,buff);
2693 		}
2694 	}
2695 
2696 	fclose(fd);
2697 
2698 	if ((p = strchr(question, ':')) != NULL)
2699 	{
2700 	   	*p++ = '\0';
2701 	   	quiz_msg(question);
2702 	   	strcpy(quiz,p);
2703 	   	if ((p = strchr(quiz, '\n')) != NULL) *p = '\0';
2704 	}
2705    	else
2706 	{
2707 		debug_msg(0, LOG_DEBUG, "Invalid quiz: %.256s", question);
2708 		quiz_msg("Invalid quiz in file.  Notify the proxy administrator.");
2709  	}
2710 }
2711 #endif
2712 
2713 
2714 
2715