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(×tr);
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