1
2 /*
3 * Copyright Colten Edwards (July 1/1998).
4 * This code is for the purpose of re-attaching to a detached BitchX session.
5 * The idea for this program was by kasper@efnet after I mentioned the trouble
6 * I was having reconnecting to a detached terminal.
7 */
8
9 /*
10 * Version 1.0 released with BitchX 75
11 * $Id: scr-bx.c 462 2013-11-13 11:43:57Z keaston $
12 */
13
14 #include "irc.h"
15 #include "struct.h"
16
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <pwd.h>
20 #ifdef USING_CURSES
21 #include <curses.h>
22 #endif
23 #include <stdarg.h>
24 #include <string.h>
25 #include "ircterm.h"
26 #include "screen.h"
27 #include "ircaux.h"
28
29 #include <sys/ioctl.h>
30
31 #ifdef HAVE_SYS_UN_H
32 #include <sys/un.h>
33 #endif
34
35 #ifdef MEM_DEBUG
36 #include <dmalloc.h>
37 #endif
38
39 #ifdef TRANSLATE
40 char translation = 0;
41 unsigned char transToClient[256]; /* Server to client translation. */
42 #endif
43
44 int dumb_mode = 0;
45 int already_detached = 1;
46 int do_check_pid = 0;
47 char socket_path[500];
48 char attach_ttyname[500];
49
50
51 struct param
52 {
53 pid_t pgrp,
54 pid;
55 uid_t uid;
56 int cols;
57 int rows;
58 char tty[80];
59 char cookie[30];
60 char password[80];
61 char termid[81];
62 };
63
64 struct param parm;
65 char *old_pass = NULL;
66 Screen *output_screen = NULL, *last_input_screen = NULL, *main_screen = NULL;
67 char empty_string[] = "";
68 int foreground = 0;
69 int use_input = 1;
70 int use_flow_control = 0;
71 static int displays = 0;
72
73 #define SOCKMODE (S_IWRITE | S_IREAD | (displays ? S_IEXEC : 0))
74
75 #ifdef CLOAKED
76 extern char **Argv; /* pointer to argument vector */
77 extern char *LastArgv; /* end of argv */
78 #endif
79
80
n_m_strdup(const char * str,const char * module,const char * file,const int line)81 char *n_m_strdup (const char *str, const char *module, const char *file, const int line)
82 {
83 char *ptr;
84 if (!str)
85 str = empty_string;
86 ptr = (char *)malloc(strlen(str) + 1);
87 return strcpy(ptr, str);
88 }
89
ircpanic(char * string,...)90 void ircpanic(char *string, ...)
91 {
92 return;
93 }
94
get_int_var(int var)95 int get_int_var(int var)
96 {
97 return 1;
98 }
99
ltoa(long foo)100 char *ltoa (long foo)
101 {
102 static char buffer[BIG_BUFFER_SIZE/8+1];
103 char *pos = buffer + BIG_BUFFER_SIZE/8-1;
104 unsigned long absv;
105 int negative;
106
107 absv = (foo < 0) ? (unsigned long)-foo : (unsigned long)foo;
108 negative = (foo < 0) ? 1 : 0;
109
110 buffer[BIG_BUFFER_SIZE/8] = 0;
111 for (; absv > 9; absv /= 10)
112 *pos-- = (absv % 10) + '0';
113 *pos = (absv) + '0';
114
115 if (negative)
116 *--pos = '-';
117
118 return pos;
119 }
120
lower(char * str)121 char *lower(char *str)
122 {
123 register char *ptr = NULL;
124
125 if (str)
126 {
127 ptr = str;
128 for (; *str; str++)
129 {
130 if (isupper(*str))
131 *str = tolower(*str);
132 }
133 }
134 return (ptr);
135 }
136
137 #ifndef HAVE_GETPASS
138 char *getpass(char *);
get_string_var(int var)139 char *get_string_var(int var)
140 {
141 return NULL;
142 }
143 #endif
144
145 #ifdef WINNT
refresh_screen(int i,char * u)146 void refresh_screen(int i, char *u)
147 {
148 return;
149 }
150 #endif
151
find_tty_name(char * name)152 char *find_tty_name(char *name)
153 {
154 static char tty[20];
155 char *q, *s;
156 *tty = 0;
157 if ((q = strrchr(name, '/')))
158 {
159 q++;
160 if ((q = strchr(q, '.')))
161 {
162 q++;
163 if ((s = strchr(q, '.')))
164 strncpy(tty, q, s-q);
165 }
166 }
167 return tty;
168 }
169
find_tty_path(char * name)170 char *find_tty_path(char *name)
171 {
172 static char ttypath[200];
173 char *q;
174 *ttypath = 0;
175 if ((q = strrchr(name, '/')))
176 strncpy(ttypath, name, q - name);
177 return ttypath;
178 }
179
display_socket_list(char * path,int unl,char * arg)180 void display_socket_list(char *path, int unl, char *arg)
181 {
182 DIR *dptr;
183 struct dirent *dir;
184 struct stat st;
185 char buffer[2000];
186 char *new_path, *p;
187 int count = 0;
188 int doit = 0;
189
190 new_path = LOCAL_COPY(path);
191 if ((p = strrchr(new_path, '/')))
192 *p = 0;
193 if (!(dptr = opendir(new_path)))
194 {
195 fprintf(stderr, "No such directory %s\r\n ", new_path);
196 exit(1);
197 }
198 while ((dir = readdir(dptr)))
199 {
200 doit = 0;
201 if (!dir->d_ino)
202 continue;
203 if (dir->d_name[0] == '.')
204 continue;
205 sprintf(buffer, "%s/%s", new_path, dir->d_name);
206 if ((stat(buffer, &st) == -1))
207 continue;
208 if (arg && strstr(dir->d_name, arg))
209 doit++;
210 if (!count && !unl)
211 fprintf(stderr, "There is more than one sockets available - \r\n");
212 else if (!count)
213 fprintf(stderr, "unlinking the following\r\n");
214 count++;
215 if (unl)
216 {
217 if (!((st.st_mode & 0700) == 0600) || doit)
218 {
219 fprintf(stderr, "%30s\r\n", dir->d_name);
220 unlink(buffer);
221 }
222 }
223 else if ((!doit && !arg) || (doit && arg))
224 fprintf(stderr, "%30s %s\r\n", dir->d_name, ((st.st_mode & 0700) == 0600) ? "detached":"Attached or dead");
225 }
226 if (!count)
227 fprintf(stderr, "No sockets to attach to.\r\n");
228 closedir(dptr);
229 exit(1);
230 }
231
find_detach_socket(char * path,char * name)232 char *find_detach_socket(char *path, char *name)
233 {
234 char *new_path;
235 DIR *dptr;
236 struct dirent *dir;
237 struct stat st;
238 char *ret = NULL, *p;
239 int count = 0;
240 new_path = LOCAL_COPY(path);
241 if ((p = strrchr(new_path, '/')))
242 *p = 0;
243 else
244 return NULL;
245 if (!(dptr = opendir(new_path)))
246 return NULL;
247 ret = malloc(2000);
248 *ret = 0;
249 while ((dir = readdir(dptr)))
250 {
251 *ret = 0;
252 if (!dir->d_ino)
253 continue;
254 if (dir->d_name[0] == '.')
255 continue;
256 sprintf(ret, "%s/%s", new_path, dir->d_name);
257 p = strrchr(ret, '/'); p++;
258 if ((stat(ret, &st) == -1) || (st.st_uid != getuid()) || S_ISDIR(st.st_mode))
259 {
260 *ret = 0;
261 continue;
262 }
263 if (name)
264 {
265 char *pid, *n_tty, *h_name;
266 pid = LOCAL_COPY(p);
267 n_tty = strchr(pid, '.'); *n_tty++ = 0;
268 h_name = strchr(n_tty, '.'); *h_name++ = 0;
269 if (strcmp(name, pid))
270 {
271 if (strcmp(n_tty, name))
272 {
273 if (strcmp(h_name, name))
274 {
275 if (strcmp(p, name))
276 {
277 if (!strstr(p, name))
278 {
279 *ret = 0;
280 continue;
281 }
282 }
283 }
284 }
285 }
286 }
287 if ((st.st_mode & 0700) == 0600)
288 break;
289 count++;
290 *ret = 0;
291 }
292 closedir(dptr);
293 if (ret && !*ret)
294 {
295 free(ret);
296 ret = NULL;
297 }
298 switch (count)
299 {
300 case 0:
301 break;
302 case 1:
303 break;
304 default:
305 display_socket_list(path, 0, name);
306 if (ret) free(ret);
307 ret = NULL;
308 }
309 return ret;
310 }
311
charset_ibmpc(void)312 void charset_ibmpc (void)
313 {
314 fwrite("\033(U", 3, 1, stdout); /* switch to IBM code page 437 */
315 }
316
SIGNAL_HANDLER(handle_pipe)317 SIGNAL_HANDLER(handle_pipe)
318 {
319
320 term_cr();
321 term_clear_to_eol();
322 term_reset2();
323 fprintf(stdout, "\rdetached from %s. To re-attach type scr-bx %s\n\r", attach_ttyname, old_pass? "password":"");
324 fflush(stdout);
325 exit(0);
326 }
327
SIGNAL_HANDLER(handle_hup)328 SIGNAL_HANDLER(handle_hup)
329 {
330 term_cr();
331 term_clear_to_eol();
332 term_reset2();
333 fprintf(stdout, "\r");
334 fflush(stdout);
335 exit(0);
336 }
337
338 volatile int ctrl_c = 0;
339
SIGNAL_HANDLER(handle_ctrlc)340 SIGNAL_HANDLER(handle_ctrlc)
341 {
342 ctrl_c++;
343 }
344
345 /* set's socket options */
set_socket_options(int s)346 void set_socket_options (int s)
347 {
348 int opt = 1;
349 int optlen = sizeof(opt);
350 #ifndef NO_STRUCT_LINGER
351 struct linger lin;
352
353 lin.l_onoff = lin.l_linger = 0;
354 setsockopt(s, SOL_SOCKET, SO_LINGER, (char *)&lin, optlen);
355 #endif
356
357 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, optlen);
358 opt = 1;
359 setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&opt, optlen);
360 }
361
362
get_cookie(char * name)363 char *get_cookie(char *name)
364 {
365 static char cookie[80];
366 FILE *fp = NULL;
367 *cookie = 0;
368 if ((fp = fopen(name, "r")))
369 {
370 fread(cookie, 40, 1, fp);
371 fclose(fp);
372 if (*cookie)
373 cookie[strlen(cookie)-1] = 0;
374 }
375 return cookie;
376 }
377
reattach_tty(char * tty,char * password)378 void reattach_tty(char *tty, char *password)
379 {
380 int s = -1;
381 char *name;
382 struct sockaddr_in addr;
383 struct hostent *hp;
384 int len = 0;
385 fd_set rd_fd;
386 struct timeval tm = {0};
387 char chr_c[] = "\003";
388
389 /*
390 * this buffer has to be big enough to handle a full screen of
391 * information from the detached process.
392 */
393 unsigned char buffer[6 * BIG_BUFFER_SIZE+1];
394 char *p;
395 int port = 0;
396 #if defined (TIOCGWINSZ)
397 struct winsize window;
398 #endif
399 memset(&parm, 0, sizeof(struct param));
400
401 if (!(name = find_detach_socket(socket_path, tty)))
402 {
403 fprintf(stderr, "No detached process to attach to.\r\n");
404 _exit(1);
405 }
406
407 strcpy(parm.cookie, get_cookie(name));
408 if (!*parm.cookie)
409 _exit(1);
410 if ((p = strrchr(name, '/')))
411 p++;
412 sscanf(p, "%d.%*s.%*s", &port);
413 displays = 1;
414 if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
415 {
416 displays = 0;
417 _exit(1);
418 }
419
420 chmod(name, SOCKMODE);
421 set_socket_options(s);
422 memset(&addr, 0, sizeof(struct sockaddr_in));
423 addr.sin_port = htons(port);
424 addr.sin_family = AF_INET;
425 if((hp = gethostbyname("localhost")))
426 memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
427 else
428 inet_aton("127.0.0.1", (struct in_addr *)&addr.sin_addr);
429 if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
430 {
431 fprintf(stderr, "connection refused for %s\r\n", name);
432 _exit(1);
433 }
434
435 parm.pid = getpid();
436 parm.pgrp = getpgrp();
437 parm.uid = getuid();
438 strcpy(parm.tty, ttyname(0));
439 strncpy(parm.termid, getenv("TERM"), 80);
440 if (password)
441 strncpy(parm.password, password, 60);
442 fprintf(stderr, "attempting to wakeup %s\r\n", find_tty_name(name));
443 #if defined (TIOCGWINSZ)
444 if (ioctl(0, TIOCGWINSZ, &window) > -1)
445 {
446 parm.cols = window.ws_col;
447 parm.rows = window.ws_row;
448 }
449 else
450 #endif
451 {
452 parm.cols = 79;
453 parm.rows = 25;
454 }
455 write(s, &parm, sizeof(struct param));
456 sleep(2);
457 alarm(15);
458 len = read(s, &parm, sizeof(struct param));
459 alarm(0);
460 if (len <= 0)
461 {
462 fprintf(stderr, "[1;37merror[0;37m reconnecting to %s\r\n", find_tty_name(name));
463 displays = 0;
464 chmod(name, SOCKMODE);
465 exit(1);
466 }
467 unlink(name);
468
469 term_init(parm.termid);
470 set_term_eight_bit(1);
471 charset_ibmpc();
472 term_clear_screen();
473 term_resize();
474 term_move_cursor(0,0);
475
476 my_signal(SIGPIPE, handle_pipe, 0);
477 my_signal(SIGINT, handle_ctrlc, 0);
478 my_signal(SIGHUP, handle_hup, 0);
479
480 /*
481 * according to MHacker we need to set errno to 0 under BSD.
482 * for some reason we get a address in use from a socket
483 *
484 */
485 errno = 0;
486 while (1)
487 {
488 FD_ZERO(&rd_fd);
489 FD_SET(0, &rd_fd);
490 FD_SET(s, &rd_fd);
491 tm.tv_sec = 2;
492
493 switch(select(s+1, &rd_fd, NULL, NULL, &tm))
494 {
495 case -1:
496 if (ctrl_c)
497 {
498 write(s, chr_c, 1);
499 ctrl_c = 0;
500 }
501 else if (errno != EINTR)
502 {
503 close(s);
504 _exit(1);
505 }
506 break;
507 case 0:
508 break;
509 default:
510 {
511 if (FD_ISSET(0, &rd_fd))
512 {
513 len = read(0, buffer, sizeof(buffer)-1);
514 write(s, buffer, len);
515 }
516 if (FD_ISSET(s, &rd_fd))
517 {
518 len = read(s, buffer, sizeof(buffer)-1);
519 write(1, buffer, len);
520 }
521 }
522 }
523 }
524 close(s);
525 fprintf(stderr, "Never should have got here");
526 _exit(1);
527
528 return; /* error return */
529 }
530
stripdev(char * ttynam)531 char *stripdev(char *ttynam)
532 {
533 if (ttynam == NULL)
534 return NULL;
535 #ifdef SVR4
536 /* unixware has /dev/pts012 as synonym for /dev/pts/12 */
537 if (!strncmp(ttynam, "/dev/pts", 8) && ttynam[8] >= '0' && ttynam[8] <= '9')
538 {
539 static char b[13];
540 sprintf(b, "pts/%d", atoi(ttynam + 8));
541 return b;
542 }
543 #endif /* SVR4 */
544 if (!strncmp(ttynam, "/dev/", 5))
545 return ttynam + 5;
546 return ttynam;
547 }
548
549
init_socketpath(void)550 void init_socketpath(void)
551 {
552 #if !defined(__EMX__) && !defined(WINNT)
553 struct stat st;
554 extern char socket_path[], attach_ttyname[];
555
556 sprintf(socket_path, "%s/.BitchX/screens", getenv("HOME"));
557 if (access(socket_path, F_OK))
558 return;
559 if (stat(socket_path, &st) != -1)
560 {
561 char host[BIG_BUFFER_SIZE+1];
562 char *ap;
563 if (!S_ISDIR(st.st_mode))
564 return;
565 gethostname(host, BIG_BUFFER_SIZE);
566 if ((ap = strchr(host, '.')))
567 *ap = 0;
568 ap = &socket_path[strlen(socket_path)];
569 sprintf(ap, "/%%d.%s.%s", stripdev(attach_ttyname), host);
570 ap++;
571 for ( ; *ap; ap++)
572 if (*ap == '/')
573 *ap = '-';
574 }
575 #endif
576 }
577
578
579 char *old_tty = NULL;
parse_args(int argc,char ** argv)580 void parse_args(int argc, char **argv)
581 {
582 int ac = 1;
583 int disp_sock = 0;
584
585 for (; ac < argc; ac++)
586 {
587
588 if (!strncasecmp(argv[ac], "tty", 3))
589 {
590 old_tty = malloc(strlen(argv[ac])+1);
591 strcpy(old_tty, argv[ac]);
592 }
593 else if (argv[ac][0] == '-' && argv[ac][1] == 'p')
594 {
595 char *pass;
596 pass = getpass("Enter password : ");
597 old_pass = malloc(strlen(pass)+1);
598 strcpy(old_pass, pass);
599 }
600 else if (argv[ac][0] == '-' && argv[ac][1] == 'h')
601 {
602 char *p;
603 if ((p = strrchr(argv[0], '/')))
604 p++;
605 else
606 p = argv[0];
607 fprintf(stderr, "Usage %s: [tty] [-p] [-h] [-l]\r\n\t\ttty is the name of a tty\r\n\t\t-p to specify a password\r\n\t\t-l to list available sockets\r\n\t\t-w to wipe out dead sockets\r\n", p);
608 exit(0);
609 }
610 else if (argv[ac][0] == '-' && argv[ac][1] == 'l')
611 disp_sock = 1;
612 else if (argv[ac][0] == '-' && argv[ac][1] == 'w')
613 disp_sock = 2;
614 else if (!old_tty)
615 {
616 old_tty = malloc(strlen(argv[ac])+1);
617 strcpy(old_tty, argv[ac]);
618 }
619 }
620 if (disp_sock)
621 display_socket_list(socket_path, disp_sock - 1, old_tty);
622 }
623
624
main(int argc,char ** argv)625 int main(int argc, char **argv)
626 {
627 #ifdef MEM_DEBUG
628 dmalloc_debug(0x1df47dfb);
629 #endif
630 *socket_path = 0;
631 strcpy(attach_ttyname, ttyname(0));
632 init_socketpath();
633 parse_args(argc, argv);
634 chdir(getenv("HOME"));
635 reattach_tty(old_tty, old_pass);
636 return 0;
637 }
638