1 /*
2  * dcc.c: Things dealing client to client connections.
3  *
4  * Written By Troy Rollo <troy@cbme.unsw.oz.au>
5  *
6  * Copyright (c) 1991, 1992 Troy Rollo.
7  * Copyright (c) 1992-2020 Matthew R. Green.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #include "irc.h"
35 IRCII_RCSID("@(#)$eterna: dcc.c,v 1.188 2020/11/17 08:12:34 mrg Exp $");
36 
37 #include <sys/stat.h>
38 
39 #ifdef HAVE_WRITEV
40 #include <sys/uio.h>
41 #endif
42 
43 #include "server.h"
44 #include "ircaux.h"
45 #include "whois.h"
46 #include "lastlog.h"
47 #include "ctcp.h"
48 #include "dcc.h"
49 #include "hook.h"
50 #include "vars.h"
51 #include "window.h"
52 #include "output.h"
53 #include "newio.h"
54 #include "irccrypt.h"
55 #include "parse.h"
56 
57 typedef	struct	DCC_struct
58 {
59 	unsigned	flags;
60 	int	read;
61 	int	write;
62 	int	file;
63 	off_t	filesize;
64 	u_char	*description;
65 	u_char	*user;
66 	u_char	*othername;
67 	u_char	*remname;
68 	u_short	remport;
69 	off_t	bytes_read;
70 	off_t	bytes_sent;
71 	time_t	lasttime;
72 	time_t	starttime;
73 	u_char	*buffer;
74 	struct DCC_struct	*next;
75 } DCC_list;
76 
77 static	u_char	*dcc_source_host;		/* source host to use for DCC */
78 
79 static	void	dcc_chat(u_char *);
80 static	void	dcc_chat_rename(u_char *);
81 static	void	dcc_filesend(u_char *);
82 static	void	dcc_getfile(u_char *);
83 static	void	dcc_close(u_char *);
84 static	void	dcc_rename(u_char *);
85 static	void	dcc_send_raw(u_char *);
86 static	void	process_incoming_chat(DCC_list *);
87 static	void	process_outgoing_file(DCC_list *);
88 static	void	process_incoming_file(DCC_list *);
89 static	void	process_incoming_raw(DCC_list *);
90 static	void	process_incoming_listen(DCC_list *);
91 
92 static	DCC_list *dcc_searchlist(u_char *, u_char *, int, int, u_char *);
93 static	void	dcc_erase(DCC_list *);
94 
95 #ifndef O_BINARY
96 #define O_BINARY 0
97 #endif /* O_BINARY */
98 
99 static struct dcc_command_stru
100 {
101 	u_char	*name;	/* *MUST* be in ALL CAPITALS */
102 	int	uniq; /* minimum length to be a unique command */
103 	void	(*function)(u_char *);
104 } dcc_commands[] = {
105 	{ UP("CHAT"),	2, dcc_chat },
106 	{ UP("LIST"),	1, dcc_list },
107 	{ UP("SEND"),	2, dcc_filesend },
108 	{ UP("GET"),	1, dcc_getfile },
109 	{ UP("CLOSE"),	2, dcc_close },
110 	{ UP("RENAME"),	2, dcc_rename },
111 	{ UP("RAW"),	2, dcc_send_raw },
112 	{ NULL,		0, (void (*)(u_char *)) NULL }
113 };
114 
115 /*
116  * this list needs to be kept in sync with the DCC_TYPES defines
117  * in dcc.h
118  */
119 static	u_char	*dcc_types[] =
120 {
121 	UP("<null>"),
122 	UP("CHAT"),
123 	UP("SEND"),
124 	UP("GET"),
125 	UP("RAW_LISTEN"),
126 	UP("RAW"),
127 	NULL
128 };
129 
130 static	struct	deadlist
131 {
132 	DCC_list *it;
133 	struct deadlist *next;
134 }	*deadlist = NULL;
135 
136 static	off_t	filesize = 0;
137 
138 static	int	in_dcc_check = 0;
139 
140 static	DCC_list *ClientList = NULL;
141 
142 static	void	add_to_dcc_buffer(DCC_list *, u_char *);
143 static	void	dcc_really_erase(void);
144 static	void	dcc_add_deadclient(DCC_list *);
145 static	int	dcc_open(DCC_list *);
146 static	u_char	*dcc_time(time_t);
147 static	u_char	*dcc_sockname(SOCKADDR_STORAGE *, int);
148 
149 static	u_char *
dcc_sockname(SOCKADDR_STORAGE * ss,int salen)150 dcc_sockname(SOCKADDR_STORAGE *ss, int salen)
151 {
152 	static u_char buf[NI_MAXHOST + NI_MAXSERV + 2];
153 	u_char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
154 
155 	if (getnameinfo((struct sockaddr *)ss, salen,
156 	    CP(hbuf), sizeof hbuf, CP(sbuf), sizeof sbuf,
157 	    NI_NUMERICSERV | NI_NUMERICHOST))
158 	{
159 		my_strmcpy(hbuf, "[unknown]", sizeof(hbuf) - 1);
160 		my_strmcpy(sbuf, "[unknown]", sizeof(sbuf) - 1);
161 	}
162 	snprintf(CP(buf), sizeof buf, "%s:%s", hbuf, sbuf);
163 	return buf;
164 }
165 
166 /*
167  * dcc_searchlist searches through the dcc_list and finds the client
168  * with the the flag described in type set.
169  */
170 static DCC_list *
dcc_searchlist(u_char * name,u_char * user,int type,int flag,u_char * othername)171 dcc_searchlist(u_char *name, u_char *user, int type, int flag, u_char *othername)
172 {
173 	DCC_list **Client, *NewClient;
174 
175 	for (Client = (&ClientList); *Client ; Client = (&(**Client).next))
176 	{
177 		if ((((**Client).flags&DCC_TYPES) == type) &&
178 		    ((!name || (!my_stricmp(name, (**Client).description))) ||
179 		    (othername && (**Client).othername && (!my_stricmp(othername, (**Client).othername)))) &&
180 		    (my_stricmp(user, (**Client).user)==0))
181 			return *Client;
182 	}
183 	if (!flag)
184 		return NULL;
185 	*Client = NewClient = new_malloc(sizeof *NewClient);
186 	NewClient->flags = type;
187 	NewClient->read = NewClient->write = NewClient->file = -1;
188 	NewClient->filesize = filesize;
189 	NewClient->next = NULL;
190 	NewClient->user = NewClient->description = NewClient->othername = NULL;
191 	NewClient->bytes_read = NewClient->bytes_sent = 0L;
192 	NewClient->starttime = 0;
193 	NewClient->buffer = 0;
194 	NewClient->remname = 0;
195 	malloc_strcpy(&NewClient->description, name);
196 	malloc_strcpy(&NewClient->user, user);
197 	malloc_strcpy(&NewClient->othername, othername);
198 	time(&NewClient->lasttime);
199 	return NewClient;
200 }
201 
202 static	void
dcc_add_deadclient(DCC_list * client)203 dcc_add_deadclient(DCC_list *client)
204 {
205 	struct deadlist *new;
206 
207 	new = new_malloc(sizeof *new);
208 	new->next = deadlist;
209 	new->it = client;
210 	deadlist = new;
211 }
212 
213 /*
214  * dcc_erase searches for the given entry in the dcc_list and
215  * removes it
216  */
217 static void
dcc_erase(DCC_list * Element)218 dcc_erase(DCC_list *Element)
219 {
220 	DCC_list	**Client;
221 
222 	for (Client = &ClientList; *Client; Client = &(**Client).next)
223 		if (*Client == Element)
224 		{
225 			*Client = Element->next;
226 
227 			if ((Element->flags & DCC_TYPES) != DCC_RAW_LISTEN)
228 				new_close(Element->write);
229 			new_close(Element->read);
230 			if (Element->file != -1)
231 				new_close(Element->file);
232 			new_free(&Element->description);
233 			new_free(&Element->user);
234 			new_free(&Element->othername);
235 			new_free(&Element->buffer);
236 			new_free(&Element->remname);
237 			new_free(&Element);
238 			return;
239 		}
240 }
241 
242 static	void
dcc_really_erase(void)243 dcc_really_erase(void)
244 {
245 	struct deadlist *dies;
246 
247 	while ((dies = deadlist) != NULL)
248 	{
249 		deadlist = deadlist->next;
250 		dcc_erase(dies->it);
251 		new_free(&dies);
252 	}
253 }
254 
255 /*
256  * Set the descriptor set to show all fds in Client connections to
257  * be checked for data.
258  */
259 void
set_dcc_bits(fd_set * rd,fd_set * wd)260 set_dcc_bits(fd_set *rd, fd_set *wd)
261 {
262 	DCC_list	*Client;
263 
264 	for (Client = ClientList; Client != NULL; Client = Client->next)
265 	{
266 #ifdef DCC_CNCT_PEND
267 		if (Client->write != -1 && (Client->flags & DCC_CNCT_PEND))
268 			FD_SET(Client->write, wd);
269 #endif /* DCC_CNCT_PEND */
270 		if (Client->read != -1)
271 			FD_SET(Client->read, rd);
272 	}
273 }
274 
275 /*
276  * Check all DCCs for data, and if they have any, perform whatever
277  * actions are required.
278  */
279 void
dcc_check(fd_set * rd,fd_set * wd)280 dcc_check(fd_set *rd, fd_set *wd)
281 {
282 	DCC_list	**Client;
283 	struct	timeval	time_out;
284 	int	previous_server;
285 	int	lastlog_level;
286 
287 	previous_server = set_from_server(-1);
288 	time_out.tv_sec = time_out.tv_usec = 0;
289 	lastlog_level = set_lastlog_msg_level(LOG_DCC);
290 	in_dcc_check = 1;
291 	for (Client = (&ClientList); *Client != NULL; )
292 	{
293 #ifdef NON_BLOCKING_CONNECTS
294 		/*
295 		 * run all connect-pending sockets.. suggested by deraadt@theos.com
296 		 */
297 		if ((*Client)->flags & DCC_CNCT_PEND)
298 		{
299 			SOCKADDR_STORAGE remaddr;
300 			socklen_t	rl = sizeof(remaddr);
301 
302 			if (getpeername((*Client)->read, (struct sockaddr *) &remaddr, &rl) != -1)
303 			{
304 				if ((*Client)->flags & DCC_OFFER)
305 				{
306 					(*Client)->flags &= ~DCC_OFFER;
307 					save_message_from();
308 					message_from((*Client)->user, LOG_DCC);
309 					if (((*Client)->flags & DCC_TYPES) != DCC_RAW)
310 						say("DCC %s connection with %s[%s] established",
311 							dcc_types[(*Client)->flags&DCC_TYPES],
312 							(*Client)->user,
313 							dcc_sockname(&remaddr, rl));
314 					restore_message_from();
315 				}
316 				(*Client)->starttime = time(NULL);
317 				(*Client)->flags &= ~DCC_CNCT_PEND;
318 				set_blocking((*Client)->read);
319 				if ((*Client)->read != (*Client)->write)
320 					set_blocking((*Client)->write);
321 			} /* else we're not connected yet */
322 		}
323 #endif /* NON_BLOCKING_CONNECTS */
324 		if ((*Client)->read != -1 && FD_ISSET((*Client)->read, rd))
325 		{
326 			switch((*Client)->flags & DCC_TYPES)
327 			{
328 			case DCC_CHAT:
329 				process_incoming_chat(*Client);
330 				break;
331 			case DCC_RAW_LISTEN:
332 				process_incoming_listen(*Client);
333 				break;
334 			case DCC_RAW:
335 				process_incoming_raw(*Client);
336 				break;
337 			case DCC_FILEOFFER:
338 				process_outgoing_file(*Client);
339 				break;
340 			case DCC_FILEREAD:
341 				process_incoming_file(*Client);
342 				break;
343 			}
344 		}
345 		if ((*Client)->flags & DCC_DELETE)
346 			dcc_add_deadclient(*Client);
347 		Client = (&(**Client).next);
348 	}
349 	in_dcc_check = 0;
350 	(void) set_lastlog_msg_level(lastlog_level);
351 	dcc_really_erase();
352 	set_from_server(previous_server);
353 }
354 
355 /*
356  * Process a DCC command from the user.
357  */
358 void
process_dcc(u_char * args)359 process_dcc(u_char *args)
360 {
361 	u_char	*command;
362 	int	i;
363 	size_t	len;
364 
365 	if (!(command = next_arg(args, &args)))
366 		return;
367 	len = my_strlen(command);
368 	upper(command);
369 	for (i = 0; dcc_commands[i].name != NULL; i++)
370 	{
371 		if (!my_strncmp(dcc_commands[i].name, command, len))
372 		{
373 			if (len < dcc_commands[i].uniq)
374 			{
375 				say("DCC command not unique: %s", command );
376 				return;
377 			}
378 			save_message_from();
379 			message_from(NULL, LOG_DCC);
380 			dcc_commands[i].function(args);
381 			restore_message_from();
382 			return;
383 		}
384 	}
385 	say("Unknown DCC command: %s", command);
386 }
387 
388 int listen_dcc(u_char *);
389 
390 int
listen_dcc(u_char * src_host)391 listen_dcc(u_char *src_host)
392 {
393 	SOCKADDR_STORAGE *ss;
394 	struct addrinfo hints, *res, *res0;
395 	int err, s;
396 
397 	if (!get_int_var(BIND_LOCAL_DCCHOST_VAR))
398 		src_host = NULL;
399 	server_get_local_ip_info(get_from_server(), &ss, NULL);
400 	memset(&hints, 0, sizeof hints);
401 	hints.ai_flags = AI_PASSIVE;
402 	hints.ai_protocol = 0;
403 	hints.ai_addrlen = 0;
404 	hints.ai_canonname = NULL;
405 	hints.ai_addr = NULL;
406 	hints.ai_next = NULL;
407 	hints.ai_socktype = SOCK_STREAM;
408 	hints.ai_family = AF_UNSPEC;
409 	errno = 0;
410 	err = getaddrinfo(CP(src_host), CP(zero()), &hints, &res0);
411 	if (err != 0)
412 	{
413 		errno = err;
414 		return -2;
415 	}
416 	for (res = res0; res; res = res->ai_next) {
417 		if (ss && SS_FAMILY(ss) != res->ai_family)
418 			continue;
419 
420 		if ((s = socket(res->ai_family, res->ai_socktype,
421 		    res->ai_protocol)) < 0)
422 			continue;
423 		set_socket_options(s);
424 		if (res->ai_family == AF_INET)
425 			((struct sockaddr_in *)res->ai_addr)->sin_port = htons(get_int_var(DCCPORT_VAR));
426 #ifdef INET6
427 		else if (res->ai_family == AF_INET6)
428 			((struct sockaddr_in6 *)res->ai_addr)->sin6_port = htons(get_int_var(DCCPORT_VAR));
429 #endif
430 		if (bind(s, res->ai_addr, res->ai_addrlen) == 0 &&
431 		    listen(s, 1) == 0)
432 		{
433 			freeaddrinfo(res0);
434 			return s;
435 		}
436 		close(s);
437 	}
438 
439 	freeaddrinfo(res0);
440 	return -1;
441 }
442 
443 static	int
dcc_open(DCC_list * Client)444 dcc_open(DCC_list *Client)
445 {
446 	u_char    *user, *Type;
447 	int	old_server, error;
448 	struct	addrinfo hints, *res0;
449 	int	ctcptype;
450 #ifndef NON_BLOCKING_CONNECTS
451 	SOCKADDR_STORAGE	remaddr;
452 	socklen_t	rl = sizeof(remaddr);
453 #endif /* NON_BLOCKING_CONNECTS */
454 
455 	if ((ctcptype = in_ctcp()) == -1)
456 	{
457 		say("You may not use the CTCP command in an ON CTCP_REPLY!");
458 		return 0;
459 	}
460 
461 	user = Client->user;
462 	old_server = get_from_server();
463 	if (old_server == -1)
464 		set_from_server(get_window_server(0));
465 
466 	Type = dcc_types[Client->flags & DCC_TYPES];
467 	if (Client->flags & DCC_OFFER)
468 	{
469 #ifdef DCC_CNCT_PEND
470 		Client->flags |= DCC_CNCT_PEND;
471 #endif /* DCC_CNCT_PEND */
472 		if ((Client->write = connect_by_number(Client->remport,
473 		    Client->remname, 1, 0, 0)) < 0)
474 		{
475 			save_message_from();
476 			message_from(user, LOG_DCC);
477 			say("Unable to create connection: %s",
478 				errno ? strerror(errno) : "Unknown Host");
479 			restore_message_from();
480 			dcc_erase(Client);
481 			set_from_server(old_server);
482 			return 0;
483 		}
484 		Client->read = Client->write;
485 		Client->bytes_read = Client->bytes_sent = 0L;
486 		Client->flags |= DCC_ACTIVE;
487 #ifndef NON_BLOCKING_CONNECTS
488 		Client->flags &= ~DCC_OFFER;
489 		Client->starttime = time(NULL);
490 		if (getpeername(Client->read, (struct sockaddr *) &remaddr, &rl) == -1)
491 		{
492 			save_message_from();
493 			message_from(user, LOG_DCC);
494 			say("DCC error: getpeername failed: %s", strerror(errno));
495 			restore_message_from();
496 			dcc_erase(Client);
497 			set_from_server(old_server);
498 			return 0;
499 		}
500 		if ((Client->flags & DCC_TYPES) != DCC_RAW)
501 		{
502 			save_message_from();
503 			message_from(user, LOG_DCC);
504 			say("DCC %s connection with %s[%s] established",
505 				Type, user, dcc_sockname(&remaddr, rl));
506 			restore_message_from();
507 		}
508 #endif /* NON_BLOCKING_CONNECTS */
509 		set_from_server(old_server);
510 		return 1;
511 	}
512 	else
513 	{
514 #ifdef DCC_CNCT_PEND
515 		Client->flags |= DCC_WAIT|DCC_CNCT_PEND;
516 #else
517 		Client->flags |= DCC_WAIT;
518 #endif /* DCC_CNCT_PEND */
519 		if ((Client->read = listen_dcc(dcc_source_host)) < 0)
520 		{
521 			save_message_from();
522 			message_from(user, LOG_DCC);
523 			say("Unable to initialise connection: %s",
524 				Client->read ? gai_strerror(errno) : strerror(errno));
525 			restore_message_from();
526 			dcc_erase(Client);
527 			set_from_server(old_server);
528 			return 0;
529 		}
530 		if (Client->flags & DCC_TWOCLIENTS)
531 		{
532 			SOCKADDR_STORAGE	locaddr;
533 			SOCKADDR_STORAGE	*myip, me;
534 			u_char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
535 			u_char *printhbuf = 0;
536 			u_char	*nopath, *sh;
537 			socklen_t	sla;
538 			int	times = 0;
539 
540 			if ((Client->flags & DCC_FILEOFFER) &&
541 			    (nopath = my_rindex(Client->description, '/')))
542 				nopath++;
543 			else
544 				nopath = Client->description;
545 
546 			sla = sizeof locaddr;
547 			getsockname(Client->read,
548 			    (struct sockaddr *) &locaddr, &sla);
549 
550 			if ((error = getnameinfo((struct sockaddr *)&locaddr,
551 			    sla, 0, 0, CP(sbuf), sizeof sbuf, NI_NUMERICSERV)))
552 			{
553 				save_message_from();
554 				message_from(user, LOG_DCC);
555 				say("Unable to get socket port address: %s",
556 					gai_strerror(error));
557 				restore_message_from();
558 				dcc_erase(Client);
559 				set_from_server(old_server);
560 				return 0;
561 			}
562 
563 			myip = 0;
564 			sh = dcc_source_host;
565 			if (sh && *sh)
566 			{
567 do_it_again:
568 				memset(&hints, 0, sizeof hints);
569 				hints.ai_flags = 0;
570 				hints.ai_protocol = 0;
571 				hints.ai_addrlen = 0;
572 				hints.ai_canonname = NULL;
573 				hints.ai_addr = NULL;
574 				hints.ai_next = NULL;
575 				hints.ai_socktype = SOCK_STREAM;
576 				hints.ai_family = PF_UNSPEC;
577 				error = getaddrinfo(CP(sh), 0, &hints, &res0);
578 				if (error == 0)
579 				{
580 					memmove(&me, (char *) res0->ai_addr, sizeof me);
581 					myip = &me;
582 					sla = res0->ai_addrlen;
583 					freeaddrinfo(res0);
584 				}
585 				else
586 				{
587 					save_message_from();
588 					message_from(user, LOG_DCC);
589 					say("Unable to create address from %s: %s", sh,
590 						gai_strerror(error));
591 					restore_message_from();
592 					dcc_erase(Client);
593 					set_from_server(old_server);
594 					return 0;
595 				}
596 			}
597 			else
598 				server_get_local_ip_info(get_from_server(), &myip, &sla);
599 
600 			if (!myip)
601 				myip = &locaddr;
602 
603 			error = getnameinfo((struct sockaddr *) myip, sla,
604 				CP(hbuf), sizeof hbuf, 0, 0, NI_NUMERICHOST);
605 			if (error)
606 			{
607 				save_message_from();
608 				message_from(user, LOG_DCC);
609 				say("Unable to getnameinfo: %s", gai_strerror(error));
610 				restore_message_from();
611 				dcc_erase(Client);
612 				set_from_server(old_server);
613 				return 0;
614 			}
615 
616 #ifdef INET6
617 			/* Make sure IPv4 goes as a single number */
618 			if (SS_FAMILY(myip) == PF_INET)
619 #endif
620 			{
621 				struct sockaddr_in *in = (struct sockaddr_in *) myip;
622 				uint32_t l;
623 
624 				malloc_strcpy(&printhbuf, hbuf);
625 				memmove(&l, (char *) &in->sin_addr.s_addr, sizeof l);
626 				snprintf(CP(hbuf), sizeof hbuf, "%lu", (unsigned long)ntohl(l));
627 			}
628 
629 			/* if the host is "0", force it to source_host or then hostname */
630 			if (my_strcmp(hbuf, zero()) == 0)
631 			{
632 				if (times == 0)
633 				{
634 					sh = get_irchost();
635 					if (!sh || !*sh)
636 						times++;
637 				}
638 				if (times == 1)
639 					sh = my_hostname();
640 				else
641 				{
642 					save_message_from();
643 					message_from(user, LOG_DCC);
644 					say("DCC: Unable to generate a source address");
645 					restore_message_from();
646 					dcc_erase(Client);
647 					set_from_server(old_server);
648 					if (printhbuf)
649 						new_free(&printhbuf);
650 					return 0;
651 				}
652 				times++;
653 				goto do_it_again;
654 			}
655 
656 
657 			if (Client->filesize)
658 				send_ctcp(ctcp_type(ctcptype), user, UP("DCC"),
659 					 "%s %s %s %s %llu", Type, nopath, hbuf, sbuf,
660 					 (unsigned long long)Client->filesize);
661 			else
662 				send_ctcp(ctcp_type(ctcptype), user, UP("DCC"),
663 					 "%s %s %s %s", Type, nopath, hbuf, sbuf);
664 			save_message_from();
665 			message_from(user, LOG_DCC);
666 			say("Sent DCC %s [%s:%s] request to %s",
667 			    Type, printhbuf ? printhbuf : hbuf, sbuf, user);
668 			restore_message_from();
669 			if (printhbuf)
670 				new_free(&printhbuf);
671 		}
672 		Client->starttime = 0;
673 		set_from_server(old_server);
674 		return 2;
675 	}
676 }
677 
678 static void
dcc_chat(u_char * args)679 dcc_chat(u_char *args)
680 {
681 	u_char	*user;
682 	DCC_list	*Client;
683 
684 	if ((user = next_arg(args, &args)) == NULL)
685 	{
686 		say("You must supply a nickname for DCC CHAT");
687 		return;
688 	}
689 	Client = dcc_searchlist(UP("chat"), user, DCC_CHAT, 1, NULL);
690 	if ((Client->flags&DCC_ACTIVE) || (Client->flags&DCC_WAIT))
691 	{
692 		say("A previous DCC CHAT to %s exists", user);
693 		return;
694 	}
695 	Client->flags |= DCC_TWOCLIENTS;
696 	dcc_open(Client);
697 }
698 
699 u_char	*
dcc_raw_listen(u_int iport)700 dcc_raw_listen(u_int iport)
701 {
702 	DCC_list	*Client;
703 	u_char	PortName[10];
704 	struct sockaddr_in locaddr;	/* XXX DCC IPv6: this one doesn't matter; for now only support DCC RAW for ipv4 */
705 	u_char	*RetName = NULL;
706 	socklen_t	size;
707 	int	lastlog_level;
708 	u_short	port = (u_short) iport;
709 
710 	lastlog_level = set_lastlog_msg_level(LOG_DCC);
711 	save_message_from();
712 	message_from(NULL, LOG_DCC);
713 
714 	if (port && port < 1025)
715 	{
716 		say("Cannot bind to a privileged port");
717 		goto out;
718 	}
719 	snprintf(CP(PortName), sizeof PortName, "%d", port);
720 	Client = dcc_searchlist(UP("raw_listen"), PortName, DCC_RAW_LISTEN, 1, NULL);
721 	if (Client->flags & DCC_ACTIVE)
722 	{
723 		say("A previous DCC RAW_LISTEN on %s exists", PortName);
724 		goto out;
725 	}
726 	if (0 > (Client->read = socket(AF_INET, SOCK_STREAM, 0)))
727 	{
728 		dcc_erase(Client);
729 		say("socket() failed: %s", strerror(errno));
730 		goto out;
731 	}
732 	set_socket_options(Client->read);
733 	memset(&locaddr, 0, sizeof(locaddr));
734 	locaddr.sin_family = AF_INET;
735 	locaddr.sin_addr.s_addr = htonl(INADDR_ANY);
736 	locaddr.sin_port = htons(port);
737 	if (bind(Client->read, (struct sockaddr *) &locaddr, sizeof(locaddr))
738 				== -1)
739 	{
740 		dcc_erase(Client);
741 		say("Could not bind port: %s", strerror(errno));
742 		goto out;
743 	}
744 	listen(Client->read, 4);
745 	size = sizeof(locaddr);
746 	Client->starttime = time(NULL);
747 	getsockname(Client->read, (struct sockaddr *) &locaddr, &size);
748 	Client->write = ntohs(locaddr.sin_port);
749 	Client->flags |= DCC_ACTIVE;
750 	snprintf(CP(PortName), sizeof PortName, "%d", Client->write);
751 	malloc_strcpy(&Client->user, PortName);
752 	malloc_strcpy(&RetName, PortName);
753 out:
754 	restore_message_from();
755 	(void) set_lastlog_msg_level(lastlog_level);
756 	return RetName;
757 }
758 
759 u_char	*
dcc_raw_connect(u_char * host,u_int iport)760 dcc_raw_connect(u_char *host, u_int iport)
761 {
762 	DCC_list	*Client;
763 	struct	addrinfo hints, *res = 0, *res0 = 0;
764 	struct	sockaddr_in address;
765 	u_char	addr[NI_MAXHOST];
766 	u_char	PortName[10], *RetName = NULL;
767 	u_short	port = (u_short)iport;
768 	int	lastlog_level, err;
769 
770 	save_message_from();
771 	message_from(NULL, LOG_DCC);
772 	lastlog_level = set_lastlog_msg_level(LOG_DCC);
773 
774 	memset(&hints, 0, sizeof hints);
775 	hints.ai_flags = 0;
776 	hints.ai_protocol = 0;
777 	hints.ai_addrlen = 0;
778 	hints.ai_canonname = NULL;
779 	hints.ai_addr = NULL;
780 	hints.ai_next = NULL;
781 	hints.ai_socktype = SOCK_STREAM;
782 	hints.ai_family = AF_INET;
783 	err = getaddrinfo(CP(host), 0, &hints, &res0);
784 	if (err == 0)
785 	{
786 		for (res = res0; res; res = res->ai_next)
787 			if (res->ai_family == PF_INET)
788 			{
789 				memmove(&address, res->ai_addr, sizeof address);
790 				break;
791 			}
792 		freeaddrinfo(res0);
793 	}
794 	if (!res || err)
795 	{
796 		say("Unknown host: %s", host);
797 		goto out;
798 	}
799 
800 	snprintf(CP(PortName), sizeof PortName, "%d", port);
801 	Client = dcc_searchlist(host, PortName, DCC_RAW, 1, NULL);
802 	if (Client->flags & DCC_ACTIVE)
803 	{
804 		say("A previous DCC RAW to %s on %s exists", host, PortName);
805 		goto out;
806 	}
807 	Client->remport = port;
808 	err = getnameinfo((struct sockaddr *) &address, sizeof address, CP(addr), NI_MAXHOST, 0, 0, NI_NUMERICHOST);
809 	if (err != 0)
810 	{
811 		my_strncpy(addr, UP("[unknown]"), sizeof(addr) - 1);
812 		yell("dcc_raw_connect: getnameinfo failed: %s", gai_strerror(err));
813 	}
814 	malloc_strcpy(&Client->remname, addr);
815 	Client->flags = DCC_OFFER | DCC_RAW;
816 	if (!dcc_open(Client))
817 		goto out;
818 	snprintf(CP(PortName), sizeof PortName, "%d", Client->read);
819 	malloc_strcpy(&Client->user, PortName);
820 	if (do_hook(DCC_RAW_LIST, "%s %s E %d", PortName, host, port))
821 		put_it("DCC RAW connection to %s on %s via %d established",
822 				host, PortName, port);
823 	malloc_strcpy(&RetName, PortName);
824 out:
825 	restore_message_from();
826 	(void) set_lastlog_msg_level(lastlog_level);
827 	return RetName;
828 }
829 
830 static	void
dcc_filesend(u_char * args)831 dcc_filesend(u_char *args)
832 {
833 	u_char	*user;
834 	u_char	*filename = NULL,
835 		*filearg;
836 	DCC_list *Client;
837 	char	cwd[PATH_MAX+1];
838 	struct	stat	sb;
839 
840 #ifdef  DAEMON_UID
841 	if (DAEMON_UID == getuid())
842 	{
843 		say("You are not permitted to use DCC to exchange files");
844 		goto out;
845 	}
846 #endif /* DAEMON_UID */
847 	if (0 == (user = next_arg(args, &args)) ||
848 	    0 == (filearg = next_arg(args, &args)))
849 	{
850 		say("You must supply a nickname and filename for DCC SEND");
851 		goto out;
852 	}
853 	if (IS_ABSOLUTE_PATH(filearg))
854 	{
855 		malloc_strcpy(&filename, filearg);
856 	}
857 	else if (*filearg == '~')
858 	{
859 		filename = expand_twiddle(filearg);
860 	}
861 	else
862 	{
863 		if (getcwd(CP(cwd), sizeof(cwd))) {
864 			cwd[0] = '.';
865 			cwd[1] = '\0';
866 		}
867 		malloc_snprintf(&filename, "%s/%s", cwd, filearg);
868 	}
869 	if (stat(CP(filename), &sb) == -1)
870 	{
871 		yell("Cannot access %s", filename);
872 		goto out;
873 	}
874 /* some unix didn't have this ???? */
875 #ifdef S_IFDIR
876 	if (sb.st_mode & S_IFDIR)
877 	{
878 		yell("Cannot send a directory");
879 		goto out;
880 	}
881 #endif /* S_IFDER */
882 	if (strstr(CP(filename), "/etc/"))
883 	{
884 		yell("Send request rejected");
885 		goto out;
886 	}
887 	if (my_strlen(filename) >= 7 && 0 == my_strcmp(filename + my_strlen(filename) - 7, "/passwd"))
888 	{
889 		yell("Send request rejected");
890 		goto out;
891 	}
892 	filesize = sb.st_size;
893 	Client = dcc_searchlist(filename, user, DCC_FILEOFFER, 1, filename);
894 	if ((Client->flags & DCC_ACTIVE) || (Client->flags & DCC_WAIT))
895 	{
896 		say("A previous DCC SEND:%s to %s exists", filename, user);
897 		goto out;
898 	}
899 	if ((Client->file = open(CP(Client->description), O_RDONLY | O_BINARY)) == -1)
900 	{
901 		say("Unable to open %s: %s\n", Client->description,
902 			errno ? strerror(errno) : "Unknown Host");
903 		new_close(Client->read);
904 		Client->read = Client->write = (-1);
905 		Client->flags |= DCC_DELETE;
906 		goto out;
907 	}
908 	filesize = 0;
909 	Client->flags |= DCC_TWOCLIENTS;
910 	dcc_open(Client);
911 out:
912 	new_free(&filename);
913 }
914 
915 
916 static	void
dcc_getfile(u_char * args)917 dcc_getfile(u_char *args)
918 {
919 	u_char	*user;
920 	u_char	*filename;
921 	DCC_list	*Client;
922 	u_char	*fullname = NULL;
923 
924 #ifdef  DAEMON_UID
925 	if (DAEMON_UID == getuid())
926 	{
927 		say("You are not permitted to use DCC to exchange files");
928 		return;
929 	}
930 #endif /* DAEMON_UID */
931 	if (0 == (user = next_arg(args, &args)))
932 	{
933 		say("You must supply a nickname for DCC GET");
934 		return;
935 	}
936 	filename = next_arg(args, &args);
937 	if (0 == (Client = dcc_searchlist(filename, user, DCC_FILEREAD, 0, NULL)))
938 	{
939 		if (filename)
940 			say("No file (%s) offered in SEND mode by %s",
941 					filename, user);
942 		else
943 			say("No file offered in SEND mode by %s", user);
944 		return;
945 	}
946 	if ((Client->flags & DCC_ACTIVE) || (Client->flags & DCC_WAIT))
947 	{
948 		if (filename)
949 			say("A previous DCC GET:%s to %s exists", filename, user);
950 		else
951 			say("A previous DCC GET to %s exists", user);
952 		return;
953 	}
954 	if (0 == (Client->flags & DCC_OFFER))
955 	{
956 		say("I'm a teapot!");
957 		dcc_erase(Client);
958 		return;
959 	}
960 
961 	fullname = expand_twiddle(Client->description);
962 	Client->file = open(CP(fullname), O_BINARY | O_WRONLY | O_TRUNC | O_CREAT, 0644);
963 	new_free(&fullname);
964 	if (-1 == Client->file)
965 	{
966 		say("Unable to open %s: %s", Client->description,
967 				errno ? strerror(errno) : "<No Error>");
968 		return;
969 	}
970 	Client->flags |= DCC_TWOCLIENTS;
971 	Client->bytes_sent = Client->bytes_read = 0L;
972 	if (!dcc_open(Client))
973 		close(Client->file);
974 }
975 
976 void
register_dcc_offer(u_char * user,u_char * type,u_char * description,u_char * address,u_char * port,u_char * size)977 register_dcc_offer(u_char *user, u_char *type, u_char *description, u_char *address, u_char *port, u_char *size)
978 {
979 	DCC_list	*Client;
980 	u_char	*c, *s, *cmd = NULL;
981 	unsigned	TempInt;
982 	int	CType;
983 	int	do_auto = 0;	/* used in dcc chat collisions */
984 	int	lastlog_level;
985 
986 	lastlog_level = set_lastlog_msg_level(LOG_DCC);
987 	if (0 != (c = my_rindex((description), '/')))
988 		description = c + 1;
989 	if ('.' == *description)
990 		*description = '_';
991 	if (size && *size)
992 		filesize = my_atoi(size);
993 	else
994 		filesize = 0;
995 	malloc_strcpy(&cmd, type);
996 	upper(cmd);
997 	if (!my_strcmp(cmd, "CHAT"))
998 		CType = DCC_CHAT;
999 #ifndef  DAEMON_UID
1000 	else if (!my_strcmp(cmd, "SEND"))
1001 #else
1002 	else if (!my_strcmp(cmd, "SEND") && DAEMON_UID != getuid())
1003 #endif /* DAEMON_UID */
1004 		CType = DCC_FILEREAD;
1005 	else
1006 	{
1007 		say("Unknown DCC %s (%s) received from %s", type, description, user);
1008 		goto out;
1009 	}
1010 	Client = dcc_searchlist(description, user, CType, 1, NULL);
1011 	filesize = 0;
1012 	if (Client->flags & DCC_WAIT)
1013 	{
1014 		new_close(Client->read);
1015 		dcc_erase(Client);
1016 		if (DCC_CHAT == CType)
1017 		{
1018 			Client = dcc_searchlist(description, user, CType, 1, NULL);
1019 			do_auto = 1;
1020 		}
1021 		else
1022 		{
1023 			say("DCC %s collision for %s:%s", type, user,
1024 				description);
1025 			send_ctcp_reply(user, UP("DCC"), "DCC %s collision occured while connecting to %s (%s)", type, my_nickname(), description);
1026 			goto out;
1027 		}
1028 	}
1029 	if (Client->flags & DCC_ACTIVE)
1030 	{
1031 		say("Received DCC %s request from %s while previous session still active", type, user);
1032 		goto out;
1033 	}
1034 	Client->flags |= DCC_OFFER;
1035 
1036 	sscanf(CP(port), "%u", &TempInt);
1037 	if (TempInt < 1024)
1038 	{
1039 		say("DCC %s (%s) request from %s rejected [addr = %s, port = %d]", type, description, user, address, TempInt);
1040 		dcc_erase(Client);
1041 		goto out;
1042 	}
1043 
1044 	for (s = address; *s; s++)
1045 		if (!isdigit(*s))
1046 			break;
1047 	if (*s)
1048 		malloc_strcpy(&Client->remname, address);
1049 	else
1050 	{
1051 		/* This is definately an IPv4 address, convert to a.b.c.d */
1052 		u_char	buf[20];
1053 		u_long	TempLong;
1054 		u_int	dots[4], i;
1055 
1056 		sscanf(CP(address), "%lu", &TempLong);
1057 		if (0 == TempLong)
1058 		{
1059 			say("DCC %s (%s) request from %s rejected [addr = %s, port = %d]", type, description, user, address, (int)TempLong);
1060 			dcc_erase(Client);
1061 			goto out;
1062 		}
1063 		for (i = 0; i < 4; i++)
1064 		{
1065 			dots[i] = TempLong & 0xff;
1066 			TempLong >>= 8;
1067 		}
1068 		snprintf(CP(buf), sizeof buf, "%u.%u.%u.%u", dots[3], dots[2], dots[1], dots[0]);
1069 		malloc_strcpy(&Client->remname, buf);
1070 	}
1071 	Client->remport = TempInt;
1072 	if (do_auto)
1073 	{
1074 		say("DCC CHAT already requested by %s, connecting to [%s:%s] ...", user, Client->remname, port);
1075 		dcc_chat(user);
1076 	}
1077 	else if (Client->filesize)
1078 		say("DCC %s (%s %lu) request received from %s [%s:%s]", type, description, (u_long)Client->filesize, user, Client->remname, port);
1079 	else
1080 		say("DCC %s (%s) request received from %s [%s:%s]", type, description, user, Client->remname, port);
1081 	if (do_beep_on_level(LOG_CTCP))
1082 		beep_em(1);
1083 out:
1084 	set_lastlog_msg_level(lastlog_level);
1085 	new_free(&cmd);
1086 }
1087 
1088 static	void
process_incoming_chat(DCC_list * Client)1089 process_incoming_chat(DCC_list *Client)
1090 {
1091 	SOCKADDR_STORAGE	remaddr;
1092 	socklen_t	sra;
1093 	u_char	tmp[BIG_BUFFER_SIZE];
1094 	u_char	*tmpuser = NULL;
1095 	u_char	*s, *bufptr;
1096 	long	bytesread;
1097 	int	old_timeout;
1098 	size_t	len;
1099 
1100 	save_message_from();
1101 	message_from(Client->user, LOG_DCC);
1102 	if (Client->flags & DCC_WAIT)
1103 	{
1104 		sra = sizeof remaddr;
1105 		Client->write = accept(Client->read, (struct sockaddr *)
1106 			&remaddr, &sra);
1107 		if (Client->write == -1)
1108 		{
1109 			say("DCC chat connect to %s failed in accept: %s",
1110 			    Client->user, strerror(errno));
1111 			Client->read = -1;
1112 			Client->flags |= DCC_DELETE;
1113 			goto out;
1114 		}
1115 		new_close(Client->read);
1116 		Client->read = Client->write;
1117 		Client->flags &= ~DCC_WAIT;
1118 		Client->flags |= DCC_ACTIVE;
1119 		say("DCC chat connection to %s[%s] established", Client->user, dcc_sockname(&remaddr, sra));
1120 		Client->starttime = time(NULL);
1121 		goto out;
1122 	}
1123 	s = Client->buffer;
1124 	bufptr = tmp;
1125 	if (s && *s)
1126 	{
1127 		len = my_strlen(s);
1128 		my_strncpy(tmp, s, len);
1129 		bufptr += len;
1130 	}
1131 	else
1132 		len = 0;
1133 	old_timeout = dgets_timeout(1);
1134 	bytesread = dgets(bufptr, ((sizeof(tmp)/2) - len), Client->read);
1135 	(void) dgets_timeout(old_timeout);
1136 	switch ((int)bytesread)
1137 	{
1138 	case -2:
1139 		/* SSL retry */
1140 		break;
1141 	case -1:
1142 		add_to_dcc_buffer(Client, bufptr);
1143 		if (Client->buffer && (my_strlen(Client->buffer) > sizeof(tmp)/2))
1144 		{
1145 			new_free(&Client->buffer);
1146 			say("*** dropped long DCC CHAT message from %s", Client->user);
1147 		}
1148 		break;
1149 	case 0:
1150 		say("DCC CHAT connection to %s lost: %s", Client->user,
1151 		    dgets_errno() == -1 ?
1152 			"Remote end closed connection" : strerror(dgets_errno()));
1153 		new_close(Client->read);
1154 		Client->read = Client->write = -1;
1155 		Client->flags |= DCC_DELETE;
1156 		break;
1157 	default:
1158 		new_free(&Client->buffer);
1159 		len = my_strlen(tmp);
1160 		if (len > sizeof(tmp)/2)
1161 			len = sizeof(tmp)/2;
1162 		Client->bytes_read += len;
1163 		malloc_snprintf(&tmpuser, "=%s", Client->user);
1164 		s = do_ctcp(tmpuser, my_nickname(), tmp);
1165 		new_free(&tmpuser);
1166 		s[my_strlen(s) - 1] = '\0';	/* remove newline */
1167 		if (s && *s)
1168 		{
1169 			/* stop dcc long messages, stupid but "safe"? */
1170 			s[sizeof(tmp)/2-1] = '\0';
1171 			if (do_hook(DCC_CHAT_LIST, "%s %s", Client->user, s))
1172 			{
1173 				if (is_away_set())
1174 				{
1175 					time_t	t;
1176 
1177 					t = time(0);
1178 					snprintf(CP(tmp), sizeof tmp, "%s <%.16s>", s, ctime(&t));
1179 					s = tmp;
1180 				}
1181 				put_it("=%s= %s", Client->user, s);
1182 				if (do_beep_on_level(LOG_CTCP))
1183 					beep_em(1);
1184 			}
1185 		}
1186 	}
1187 out:
1188 	restore_message_from();
1189 }
1190 
1191 static	void
process_incoming_listen(DCC_list * Client)1192 process_incoming_listen(DCC_list *Client)
1193 {
1194 	SOCKADDR_STORAGE	remaddr;
1195 	DCC_list *NewClient;
1196 	u_char host[NI_MAXHOST], FdName[10], *Name;
1197 	socklen_t	sra;
1198 	int	new_socket, err;
1199 
1200 	sra = sizeof remaddr;
1201 	new_socket = accept(Client->read, (struct sockaddr *) &remaddr, &sra);
1202 	err = getnameinfo((struct sockaddr *) &remaddr, sra, CP(host), NI_MAXHOST, 0, 0, 0);
1203 	if (err != 0)
1204 	{
1205 		my_strncpy(host, UP("[unknown]"), sizeof(host) - 1);
1206 		yell("process_incoming_listen: getnameinfo failed?");
1207 	}
1208 	Name = host;
1209 
1210 	snprintf(CP(FdName), sizeof FdName, "%d", new_socket);
1211 	NewClient = dcc_searchlist(Name, FdName, DCC_RAW, 1, NULL);
1212 	NewClient->starttime = time(NULL);
1213 	NewClient->read = NewClient->write = new_socket;
1214 	NewClient->flags |= DCC_ACTIVE;
1215 	NewClient->bytes_read = NewClient->bytes_sent = 0L;
1216 	malloc_strcpy(&NewClient->remname, Name);
1217 	if (SS_FAMILY(&remaddr) == PF_INET)
1218 	{
1219 		struct sockaddr_in *in = (struct sockaddr_in *) &remaddr;
1220 		NewClient->remport = in->sin_port;
1221 	}
1222 #ifdef INET6
1223 	else
1224 	if (SS_FAMILY(&remaddr) == PF_INET6)
1225 	{
1226 		struct sockaddr_in6 *in = (struct sockaddr_in6 *) &remaddr;
1227 		NewClient->remport = in->sin6_port;
1228 	}
1229 #endif
1230 	save_message_from();
1231 	message_from(NewClient->user, LOG_DCC);
1232 	if (do_hook(DCC_RAW_LIST, "%s %s N %d", NewClient->user,
1233 						NewClient->description,
1234 						Client->write))
1235 		say("DCC RAW connection to %s on %s via %d established",
1236 					NewClient->description,
1237 					NewClient->user,
1238 					Client->write);
1239 	restore_message_from();
1240 }
1241 
1242 static	void
process_incoming_raw(DCC_list * Client)1243 process_incoming_raw(DCC_list *Client)
1244 {
1245 	u_char	tmp[BIG_BUFFER_SIZE];
1246 	u_char	*s, *bufptr;
1247 	long	bytesread;
1248 	int     old_timeout;
1249 	size_t	len;
1250 
1251 	save_message_from();
1252 	message_from(Client->user, LOG_DCC);
1253 
1254 	s = Client->buffer;
1255 	bufptr = tmp;
1256 	if (s && *s)
1257 	{
1258 		len = my_strlen(s);
1259 		my_strncpy(tmp, s, len);
1260 		bufptr += len;
1261 	}
1262 	else
1263 		len = 0;
1264 	old_timeout = dgets_timeout(1);
1265 	switch((int)(bytesread = dgets(bufptr, ((sizeof(tmp)/2) - len), Client->read)))
1266 	{
1267 	case -2:
1268 		/* SSL retry */
1269 		break;
1270 	case -1:
1271 		add_to_dcc_buffer(Client, bufptr);
1272 		if (Client->buffer && (my_strlen(Client->buffer) > sizeof(tmp)/2))
1273 		{
1274 			new_free(&Client->buffer);
1275 			say("*** dropping long DCC message from %s", Client->user);
1276 		}
1277 		break;
1278 	case 0:
1279 		if (do_hook(DCC_RAW_LIST, "%s %s C",
1280 				Client->user, Client->description))
1281 			say("DCC RAW connection to %s on %s lost",
1282 				Client->user, Client->description);
1283 		new_close(Client->read);
1284 		Client->read = Client->write = -1;
1285 		Client->flags |= DCC_DELETE;
1286 		(void) dgets_timeout(old_timeout);
1287 		break;
1288 	default:
1289 		new_free(&Client->buffer);
1290 		len = my_strlen(tmp);
1291 		if (len > sizeof(tmp) / 2)
1292 			len = sizeof(tmp) / 2;
1293 		tmp[len - 1] = '\0';
1294 		Client->bytes_read += len;
1295 		if (do_hook(DCC_RAW_LIST, "%s %s D %s",
1296 				Client->user, Client->description, tmp))
1297 			say("Raw data on %s from %s: %s",
1298 				Client->user, Client->description, tmp);
1299 		(void) dgets_timeout(old_timeout);
1300 	}
1301 	restore_message_from();
1302 }
1303 
1304 static	void
process_outgoing_file(DCC_list * Client)1305 process_outgoing_file(DCC_list *Client)
1306 {
1307 	SOCKADDR_STORAGE	remaddr;
1308 	socklen_t sra;
1309 	u_char	tmp[FS_BUFFER_SIZE];
1310 	uint32_t bytesrecvd;
1311 	int	bytesread;
1312 	int	BlockSize;
1313 
1314 	save_message_from();
1315 	message_from(Client->user, LOG_DCC);
1316 	if (Client->flags & DCC_WAIT)
1317 	{
1318 		sra = sizeof remaddr;
1319 		Client->write = accept(Client->read,
1320 				(struct sockaddr *) &remaddr, &sra);
1321 		new_close(Client->read);
1322 		Client->read = Client->write;
1323 		Client->flags &= ~DCC_WAIT;
1324 		Client->flags |= DCC_ACTIVE;
1325 		Client->bytes_sent = 0L;
1326 		Client->starttime = time(NULL);
1327 		say("DCC SEND connection to %s[%s] established", Client->user,
1328 		    dcc_sockname(&remaddr, sra));
1329 	}
1330 	else
1331 	{
1332 		if ((bytesread = recv(Client->read, (char *) &bytesrecvd, sizeof(uint32_t), 0)) < sizeof(uint32_t))
1333 		{
1334 	       		say("DCC SEND:%s connection to %s lost: %s", Client->description, Client->user, strerror(errno));
1335 			new_close(Client->read);
1336 			Client->read = Client->write = (-1);
1337 			Client->flags |= DCC_DELETE;
1338 			new_close(Client->file);
1339 			goto out;
1340 		}
1341 		else
1342 			if (ntohl(bytesrecvd) != Client->bytes_sent)
1343 				goto out;
1344 	}
1345 	BlockSize = get_int_var(DCC_BLOCK_SIZE_VAR);
1346 	if (BlockSize > sizeof tmp)
1347 		BlockSize = sizeof tmp;
1348 	else if (BlockSize < 16)
1349 		BlockSize = 16;
1350 	if ((bytesread = read(Client->file, tmp, sizeof tmp)) != 0)
1351 	{
1352 		if (send(Client->write, CP(tmp), (size_t)bytesread, 0) <= 0)
1353 		{
1354 			say("DCC SEND:%s to %s failed: %s",
1355 				Client->description, Client->user, strerror(errno));
1356 			goto end_connection;
1357 		}
1358 		Client->bytes_sent += bytesread;
1359 	}
1360 	else
1361 	{
1362 		time_t	xtime = time(NULL) - Client->starttime;
1363 		double	sent = (double)Client->bytes_sent;
1364 
1365 		if (sent <= 0)
1366 			sent = 1;
1367 		sent /= (double)1024.0;
1368 		if (xtime <= 0)
1369 			xtime = 1;
1370 		say("DCC SEND:%s to %s completed %2.4g kb/sec",
1371 			Client->description, Client->user, (sent / (double)xtime));
1372 end_connection:
1373 		new_close(Client->read);
1374 		Client->read = Client->write = -1;
1375 		Client->flags |= DCC_DELETE;
1376 		new_close(Client->file);
1377 	}
1378 out:
1379 	restore_message_from();
1380 }
1381 
1382 static	void
process_incoming_file(DCC_list * Client)1383 process_incoming_file(DCC_list *Client)
1384 {
1385 	u_char	tmp[FS_BUFFER_SIZE];
1386 	uint32_t bytestemp;
1387 	ssize_t	bytesread;
1388 
1389 	save_message_from();
1390 	message_from(Client->user, LOG_DCC);
1391 
1392 	if ((bytesread = recv(Client->read, CP(tmp), sizeof tmp, 0)) <= 0)
1393 	{
1394 		time_t	xtime = time(NULL) - Client->starttime;
1395 		double	sent = (double)Client->bytes_read;
1396 
1397 		if (sent <= 0)
1398 			sent = 1;
1399 		sent /= (double)1024.0;
1400 		if (xtime <= 0)
1401 			xtime = 1;
1402 		say("DCC GET:%s from %s completed %2.4g kb/sec",
1403 			Client->description, Client->user, (sent / (double)xtime));
1404 		goto file_cleanup;
1405 	}
1406 	if (write(Client->file, tmp, (size_t)bytesread) != bytesread)
1407 	{
1408 		say("DCC GET:%s from %s file write failed: %s",
1409 			Client->description, Client->user, strerror(errno));
1410 		goto file_cleanup;
1411 	}
1412 	Client->bytes_read += bytesread;
1413 	bytestemp = htonl(Client->bytes_read);
1414 	if (send(Client->write, (char *)&bytestemp, sizeof(uint32_t), 0) != sizeof(uint32_t))
1415 	{
1416 		say("DCC GET:%s from %s remote ack send failed: %s",
1417 			Client->description, Client->user, strerror(errno));
1418 		goto file_cleanup;
1419 	}
1420 	goto out;
1421 
1422 file_cleanup:
1423 	new_close(Client->read);
1424 	new_close(Client->file);
1425 	Client->read = Client->write = (-1);
1426 	Client->flags |= DCC_DELETE;
1427 out:
1428 	restore_message_from();
1429 }
1430 
1431 /* flag == 1 means show it.  flag == 0 used by redirect */
1432 
1433 void
dcc_message_transmit(u_char * user,u_char * text,int type,int flag)1434 dcc_message_transmit(u_char *user, u_char *text, int type, int flag)
1435 {
1436 	DCC_list	*Client;
1437 	u_char	tmp[BIG_BUFFER_SIZE]; /* XXX */
1438 	u_char	nickbuf[128];
1439 	u_char	thing = '\0';
1440 	u_char	*host = NULL;
1441 	crypt_key	*key;
1442 	u_char	*line;
1443 	int	lastlog_level;
1444 	int	list = 0;
1445 	size_t	len;
1446 
1447 	save_message_from();
1448 	message_from(user, LOG_DCC);
1449 	lastlog_level = set_lastlog_msg_level(LOG_DCC);
1450 	switch(type)
1451 	{
1452 	case DCC_CHAT:
1453 		host = UP("chat");
1454 		thing = '=';
1455 		list = SEND_DCC_CHAT_LIST;
1456 		break;
1457 	case DCC_RAW:
1458 		host = next_arg(text, &text);
1459 		if (!host)
1460 		{
1461 			say("No host specified for DCC RAW");
1462 			goto out;
1463 		}
1464 		break;
1465 	}
1466 	if (!(Client = dcc_searchlist(host, user, type, 0, NULL)) || !(Client->flags&DCC_ACTIVE))
1467 	{
1468 		say("No active DCC %s:%s connection for %s", dcc_types[type], host ? host : (u_char *) "<any>", user);
1469 		goto out;
1470 	}
1471 #ifdef DCC_CNCT_PEND
1472 	/*
1473 	 * XXX - should make this buffer
1474 	 *     - just for dcc chat ?  maybe raw dcc too.  hmm.
1475 	 */
1476 	if (Client->flags & DCC_CNCT_PEND)
1477 	{
1478 		say("DCC %s:%s connection to %s is still connecting...", dcc_types[type], host ? host : (u_char *) "<any>", user);
1479 		goto out;
1480 	}
1481 #endif /* DCC_DCNT_PEND */
1482 	strmcpy(tmp, text, sizeof tmp);
1483 	if (type == DCC_CHAT) {
1484 		nickbuf[0] = '=';
1485 		strmcpy(nickbuf+1, user, sizeof(nickbuf) - 2);
1486 
1487 		if ((key = is_crypted(nickbuf)) == 0 || (line = crypt_msg(tmp, key, 1)) == 0)
1488 			line = tmp;
1489 	}
1490 	else
1491 		line = tmp;
1492 #ifdef HAVE_WRITEV
1493 	{
1494 		struct iovec iov[2];
1495 
1496 		iov[0].iov_base = CP(line);
1497 		iov[0].iov_len = len = my_strlen(line);
1498 		iov[1].iov_base = "\n";
1499 		iov[1].iov_len = 1;
1500 		len++;
1501 		(void)writev(Client->write, iov, 2);
1502 	}
1503 #else
1504 	strmcat(line, "\n", (size_t)((line == tmp) ? sizeof tmp : CRYPT_BUFFER_SIZE));
1505 	len = my_strlen(line);
1506 	(void)send(Client->write, line, len, 0);
1507 #endif
1508 	Client->bytes_sent += len;
1509 	if (flag && type != DCC_RAW) {
1510 		if (do_hook(list, "%s %s", Client->user, text))
1511 			put_it("=> %c%s%c %s", thing, Client->user, thing, text);
1512 	}
1513 out:
1514 	set_lastlog_msg_level(lastlog_level);
1515 	restore_message_from();
1516 	return;
1517 }
1518 
1519 void
dcc_chat_transmit(u_char * user,u_char * text)1520 dcc_chat_transmit(u_char *user,	u_char *text)
1521 {
1522 	dcc_message_transmit(user, text, DCC_CHAT, 1);
1523 }
1524 
1525 static	void
dcc_send_raw(u_char * args)1526 dcc_send_raw(u_char *args)
1527 {
1528 	u_char	*name;
1529 
1530 	if (!(name = next_arg(args, &args)))
1531 	{
1532 		int	lastlog_level;
1533 
1534 		lastlog_level = set_lastlog_msg_level(LOG_DCC);
1535 		say("No name specified for DCC RAW");
1536 		(void) set_lastlog_msg_level(lastlog_level);
1537 		return;
1538 	}
1539 	dcc_message_transmit(name, args, DCC_RAW, 1);
1540 }
1541 
1542 /*
1543  * dcc_time: Given a time value, it returns a string that is in the
1544  * format of "hours:minutes:seconds month day year" .  Used by
1545  * dcc_list() to show the start time.
1546  */
1547 static	u_char	*
dcc_time(time_t the_time)1548 dcc_time(time_t the_time)
1549 {
1550 	struct	tm	*btime;
1551 	u_char	*buf = NULL;
1552 	static	char	*months[] =
1553 	{
1554 		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
1555 		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1556 	};
1557 
1558 	btime = localtime(&the_time);
1559 	malloc_snprintf(&buf, "%-2.2d:%-2.2d:%-2.2d %s %-2.2d %d",
1560 			btime->tm_hour, btime->tm_min, btime->tm_sec,
1561 			months[btime->tm_mon], btime->tm_mday,
1562 			btime->tm_year + 1900);
1563 	return buf;
1564 }
1565 
1566 #define DCC_FORM "%-7.7s %-9.9s %-10.10s %-20.20s %-8.8s %-8.8s %s"
1567 #define DCC_FORM_HOOK "%s %s %s %s %s %s %s"
1568 #define DCC_FORM_HEADER \
1569 	"Type", "Nick", "Status", "Start time", "Sent", "Read", "Arguments"
1570 
1571 void
dcc_list(u_char * args)1572 dcc_list(u_char *args)
1573 {
1574 	DCC_list	*Client;
1575 	unsigned	flags;
1576 	int	lastlog_level;
1577 
1578 	lastlog_level = set_lastlog_msg_level(LOG_DCC);
1579 	if (do_hook(DCC_LIST_LIST, DCC_FORM_HOOK, DCC_FORM_HEADER))
1580 		put_it(DCC_FORM, DCC_FORM_HEADER);
1581 	for (Client = ClientList ; Client != NULL ; Client = Client->next)
1582 	{
1583 		u_char	sent[9],
1584 			rd[9];
1585 		u_char	*timestr;
1586 
1587 		snprintf(CP(sent), sizeof sent, "%ld", (long)Client->bytes_sent);
1588 		snprintf(CP(rd), sizeof rd, "%ld", (long)Client->bytes_read);
1589 		timestr = (Client->starttime) ? dcc_time(Client->starttime) : empty_string();
1590 		flags = Client->flags;
1591 
1592 #ifdef DCC_DCNT_PEND
1593 #define DCC_CONT_PEND_FORM	flags & DCC_CNCT_PEND ?	"Connecting" :
1594 #else /* DCC_DCNT_PEND */
1595 #define DCC_CONT_PEND_FORM	/* nothing */
1596 #endif /* DCC_DCNT_PEND */
1597 
1598 #define DCC_FORM_BODY		dcc_types[flags & DCC_TYPES],		\
1599 				Client->user,				\
1600 				flags & DCC_OFFER ? "Offered" :		\
1601 				flags & DCC_DELETE ? "Closed" :		\
1602 				flags & DCC_ACTIVE ? "Active" :		\
1603 				flags & DCC_WAIT ? "Waiting" :		\
1604 				DCC_CONT_PEND_FORM			\
1605 				"Unknown",				\
1606 				timestr,				\
1607 				sent,					\
1608 				rd,					\
1609 				Client->description
1610 
1611 		if (do_hook(DCC_LIST_LIST, DCC_FORM_HOOK, DCC_FORM_BODY))
1612 			put_it(DCC_FORM, DCC_FORM_BODY);
1613 		if (*timestr)
1614 			new_free(&timestr);
1615 	}
1616 	(void) set_lastlog_msg_level(lastlog_level);
1617 }
1618 
1619 #undef DCC_FORM
1620 #undef DCC_FORM_HOOK
1621 #undef DCC_FORM_HEADER
1622 #undef DCC_CONT_PEND_FORM
1623 #undef DCC_FORM_BODY
1624 
1625 static	void
dcc_close(u_char * args)1626 dcc_close(u_char *args)
1627 {
1628 	DCC_list	*Client;
1629 	unsigned	flags;
1630 	u_char	*Type;
1631 	u_char	*user;
1632 	u_char	*description;
1633 	int	CType;
1634 	u_char	*cmd = NULL;
1635 	int	lastlog_level;
1636 
1637 	lastlog_level = set_lastlog_msg_level(LOG_DCC);
1638 	if (!(Type = next_arg(args, &args)) || !(user=next_arg(args, &args)))
1639 	{
1640 		say("you must specify a type and nick for DCC CLOSE");
1641 		goto out;
1642 	}
1643 	if (in_dcc_check)
1644 	{
1645 		yell("Can't close DCC inside DCC HOOK.");
1646 		goto out;
1647 	}
1648 	description = next_arg(args, &args);
1649 	malloc_strcpy(&cmd, Type);
1650 	upper(cmd);
1651 	for (CType = 0; dcc_types[CType] != NULL; CType++)
1652 		if (!my_strcmp(cmd, dcc_types[CType]))
1653 			break;
1654 	if (!dcc_types[CType])
1655 		say("Unknown DCC type: %s", Type);
1656 	else if ((Client = dcc_searchlist(description, user, CType, 0, description)))
1657 	{
1658 		flags = Client->flags;
1659 		if (flags & DCC_DELETE)
1660 			goto out;
1661 		if ((flags & DCC_WAIT) || (flags & DCC_ACTIVE))
1662 		{
1663 			new_close(Client->read);
1664 			if (Client->file)
1665 				new_close(Client->file);
1666 		}
1667 		say("DCC %s:%s to %s closed", Type,
1668 			description ? description : (u_char *) "<any>", user);
1669 		dcc_erase(Client);
1670 	}
1671 	else
1672 		say("No DCC %s:%s to %s found", Type,
1673 			description ? description : (u_char *) "<any>", user);
1674 	new_free(&cmd);
1675 out:
1676 	(void) set_lastlog_msg_level(lastlog_level);
1677 }
1678 
1679 /* this depends on dcc_rename() setting loglevel */
1680 static void
dcc_chat_rename(u_char * args)1681 dcc_chat_rename(u_char *args)
1682 {
1683 	DCC_list	*Client;
1684 	u_char	*user;
1685 	u_char	*temp;
1686 
1687 	if (!(user = next_arg(args, &args)) || !(temp = next_arg(args, &args)))
1688 	{
1689 		say("you must specify a current DCC CHAT connection, and a new name for it");
1690 		return;
1691 	}
1692 	if (dcc_searchlist(UP("chat"), temp, DCC_CHAT, 0, NULL))
1693 	{
1694 		say("You already have a DCC CHAT connection with %s, unable to rename.", temp);
1695 		return;
1696 	}
1697 	if ((Client = dcc_searchlist(UP("chat"), user, DCC_CHAT, 0, NULL)))
1698 	{
1699 		new_free(&(Client->user));
1700 		malloc_strcpy(&(Client->user), temp);
1701 		say("DCC CHAT connection with %s renamed to %s", user, temp);
1702 	}
1703 	else
1704 		say("No DCC CHAT connection with %s", user);
1705 }
1706 
1707 
1708 static	void
dcc_rename(u_char * args)1709 dcc_rename(u_char *args)
1710 {
1711 	DCC_list	*Client;
1712 	u_char	*user;
1713 	u_char	*description;
1714 	u_char	*newdesc;
1715 	u_char	*temp;
1716 	int	lastlog_level;
1717 
1718 	lastlog_level = set_lastlog_msg_level(LOG_DCC);
1719 	if ((user = next_arg(args, &args)) && my_strnicmp(user, UP("-chat"), my_strlen(user)) == 0)
1720 	{
1721 		dcc_chat_rename(args);
1722 		return;
1723 	}
1724 	if (!user || !(temp = next_arg(args, &args)))
1725 	{
1726 		say("you must specify a nick and new filename for DCC RENAME");
1727 		goto out;
1728 	}
1729 	if ((newdesc = next_arg(args, &args)) != NULL)
1730 		description = temp;
1731 	else
1732 	{
1733 		newdesc = temp;
1734 		description = NULL;
1735 	}
1736 	if ((Client = dcc_searchlist(description, user, DCC_FILEREAD, 0, NULL)))
1737 	{
1738 		if (!(Client->flags & DCC_OFFER))
1739 		{
1740 			say("Too late to rename that file");
1741 			goto out;
1742 		}
1743 		new_free(&(Client->description));
1744 		malloc_strcpy(&(Client->description), newdesc);
1745 		say("File %s from %s renamed to %s",
1746 			 description ? description : (u_char *) "<any>", user, newdesc);
1747 	}
1748 	else
1749 		say("No file %s from %s found",
1750 			description ? description : (u_char *) "<any>", user);
1751 out:
1752 	(void) set_lastlog_msg_level(lastlog_level);
1753 }
1754 
1755 /*
1756  * close_all_dcc:  We call this when we create a new process so that
1757  * we don't leave any fd's lying around, that won't close when we
1758  * want them to..
1759  */
1760 
1761 void
close_all_dcc(void)1762 close_all_dcc(void)
1763 {
1764 	DCC_list *Client;
1765 
1766 	while ((Client = ClientList))
1767 		dcc_erase(Client);
1768 }
1769 
1770 static	void
add_to_dcc_buffer(DCC_list * Client,u_char * buf)1771 add_to_dcc_buffer(DCC_list *Client, u_char *buf)
1772 {
1773 	if (buf && *buf)
1774 	{
1775 		if (Client->buffer)
1776 			malloc_strcat(&Client->buffer, buf);
1777 		else
1778 			malloc_strcpy(&Client->buffer, buf);
1779 	}
1780 }
1781 
1782 /*
1783  * backend for the $dcclist() function.
1784  */
1785 u_char *
dcc_list_func(u_char * nick)1786 dcc_list_func(u_char *nick)
1787 {
1788 	u_char *result;
1789 	DCC_list *Client;
1790 	size_t len = 0;
1791 	int i;
1792 
1793 	for (i = 0, Client = ClientList; Client != NULL; Client = Client->next)
1794 		if (!my_stricmp(nick, Client->user))
1795 			len += 3;
1796 
1797 	result = new_malloc(len + 1);
1798 
1799 	for (i = 0, Client = ClientList; Client != NULL; Client = Client->next)
1800 		if (!my_stricmp(nick, Client->user))
1801 		{
1802 			int b = Client->flags;
1803 			int a = (b & DCC_TYPES);
1804 
1805 			result[i++] =
1806 					  (a == DCC_CHAT)		? 'C' /* CHAT */
1807 					: (a == DCC_FILEOFFER)		? 'S' /* SEND */
1808 					: (a == DCC_FILEREAD)		? 'G' /* GET */
1809 					: (a == DCC_RAW_LISTEN)		? 'L' /* RAW_LISTEN */
1810 					: (a == DCC_RAW)      		? 'R' /* RAW */
1811 					: 'x';
1812 
1813 			result[i++] =
1814 					  (b & DCC_OFFER)		? 'O' /* OFFERED */
1815 					: (b & DCC_DELETE)		? 'C' /* CLOSED */
1816 					: (b & DCC_ACTIVE)		? 'A' /* ACTIVE */
1817 					: (b & DCC_WAIT)		? 'W' /* WAITING */
1818 					: 'x';
1819 
1820 			result[i++] = ' ';
1821 		}
1822 
1823 	result[i] = '\0';
1824 
1825 	return (result);
1826 }
1827 
1828 /*
1829  * backend for the $chatpeers() function.
1830  */
1831 u_char *
dcc_chatpeers_func(void)1832 dcc_chatpeers_func(void)
1833 {
1834 	u_char *result;
1835 	DCC_list *Client;
1836 	int	notfirst = 0;
1837 	size_t len = 0;
1838 
1839 	/* calculate size */
1840 	for (Client = ClientList; Client != NULL; Client = Client->next)
1841 		if ((Client->flags & (DCC_CHAT|DCC_ACTIVE)) == (DCC_CHAT|DCC_ACTIVE))
1842 			len += (my_strlen(Client->user) + 1);
1843 	result = new_malloc(len);
1844 	*result = '\0';
1845 
1846 	for (Client = ClientList; Client != NULL; Client = Client->next)
1847 		if ((Client->flags & (DCC_CHAT|DCC_ACTIVE)) == (DCC_CHAT|DCC_ACTIVE))
1848 		{
1849 			if (notfirst)
1850 				my_strmcat(result, ",", len);
1851 			else
1852 				notfirst = 1;
1853 			my_strmcat(result, Client->user, len);
1854 		}
1855 
1856 	return (result);
1857 }
1858 
1859 /*
1860  * set_dcchost: This sets the source host for subsequent connections.
1861  */
1862 void
set_dcchost(u_char * dcchost)1863 set_dcchost(u_char *dcchost)
1864 {
1865 	if (!dcchost || !*dcchost)
1866 		new_free(&dcc_source_host);
1867 	else
1868 		malloc_strcpy(&dcc_source_host, dcchost);
1869 }
1870 
1871 u_char *
get_dcchost(void)1872 get_dcchost(void)
1873 {
1874 	return dcc_source_host;
1875 }
1876