1/* Copyright (c) 1993-2002 2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de) 3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de) 4 * Copyright (c) 1987 Oliver Laumann 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2, or (at your option) 9 * any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program (see the file COPYING); if not, write to the 18 * Free Software Foundation, Inc., 19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 20 * 21 **************************************************************** 22 */ 23 24#include "config.h" 25#include <sys/types.h> 26#include <sys/stat.h> 27#include <fcntl.h> 28#if !defined(NAMEDPIPE) 29#include <sys/socket.h> 30#include <sys/un.h> 31#endif 32 33#ifndef SIGINT 34# include <signal.h> 35#endif 36 37#include "screen.h" 38 39#ifdef HAVE_DIRENT_H 40# include <dirent.h> 41#else 42# include <sys/dir.h> 43# define dirent direct 44#endif 45 46#include "extern.h" 47 48static int CheckPid __P((int)); 49static void ExecCreate __P((struct msg *)); 50static void DoCommandMsg __P((struct msg *)); 51#if defined(_SEQUENT_) && !defined(NAMEDPIPE) 52# define connect sconnect /* _SEQUENT_ has braindamaged connect */ 53static int sconnect __P((int, struct sockaddr *, int)); 54#endif 55static void FinishAttach __P((struct msg *)); 56static void AskPassword __P((struct msg *)); 57 58 59extern char *RcFileName, *extra_incap, *extra_outcap; 60extern int ServerSocket, real_uid, real_gid, eff_uid, eff_gid; 61extern int dflag, iflag, rflag, lsflag, quietflag, wipeflag, xflag; 62extern char *attach_tty, *LoginName, HostName[]; 63extern struct display *display, *displays; 64extern struct win *fore, *wtab[], *console_window, *windows; 65extern struct layer *flayer; 66extern struct NewWindow nwin_undef; 67#ifdef MULTIUSER 68extern char *multi; 69#endif 70 71extern char *getenv(); 72 73extern char SockPath[]; 74extern struct event serv_read; 75extern char *rc_name; 76extern struct comm comms[]; 77 78#ifdef MULTIUSER 79# define SOCKMODE (S_IWRITE | S_IREAD | (displays ? S_IEXEC : 0) | (multi ? 1 : 0)) 80#else 81# define SOCKMODE (S_IWRITE | S_IREAD | (displays ? S_IEXEC : 0)) 82#endif 83 84 85/* 86 * Socket directory manager 87 * 88 * fdp: pointer to store the first good socket. 89 * nfoundp: pointer to store the number of sockets found matching. 90 * notherp: pointer to store the number of sockets not matching. 91 * match: string to match socket name. 92 * 93 * The socket directory must be in SockPath! 94 * The global variables LoginName, multi, rflag, xflag, dflag, 95 * quietflag, SockPath are used. 96 * 97 * The first good socket is stored in fdp and its name is 98 * appended to SockPath. 99 * If none exists or fdp is NULL SockPath is not changed. 100 * 101 * Returns: number of good sockets. 102 * 103 */ 104 105int 106FindSocket(fdp, nfoundp, notherp, match) 107int *fdp; 108int *nfoundp, *notherp; 109char *match; 110{ 111 DIR *dirp; 112 struct dirent *dp; 113 struct stat st; 114 int mode; 115 int sdirlen; 116 int matchlen = 0; 117 char *name, *n; 118 int firsts = -1, sockfd; 119 char *firstn = NULL; 120 int nfound = 0, ngood = 0, ndead = 0, nwipe = 0, npriv = 0; 121 struct sent 122 { 123 struct sent *next; 124 int mode; 125 char *name; 126 } *slist, **slisttail, *sent, *nsent; 127 128 if (match) 129 { 130 matchlen = strlen(match); 131#ifdef NAME_MAX 132 if (matchlen > NAME_MAX) 133 matchlen = NAME_MAX; 134#endif 135 } 136 137 /* 138 * SockPath contains the socket directory. 139 * At the end of FindSocket the socket name will be appended to it. 140 * Thus FindSocket() can only be called once! 141 */ 142 sdirlen = strlen(SockPath); 143 144#ifdef USE_SETEUID 145 xseteuid(real_uid); 146 xsetegid(real_gid); 147#endif 148 149 if ((dirp = opendir(SockPath)) == 0) 150 Panic(errno, "Cannot opendir %s", SockPath); 151 152 slist = 0; 153 slisttail = &slist; 154 while ((dp = readdir(dirp))) 155 { 156 name = dp->d_name; 157 debug1("- %s\n", name); 158 if (*name == 0 || *name == '.' || strlen(name) > 2*MAXSTR) 159 continue; 160 if (matchlen) 161 { 162 n = name; 163 /* if we don't want to match digits. Skip them */ 164 if ((*match <= '0' || *match > '9') && (*n > '0' && *n <= '9')) 165 { 166 while (*n >= '0' && *n <= '9') 167 n++; 168 if (*n == '.') 169 n++; 170 } 171 /* the tty prefix is optional */ 172 if (strncmp(match, "tty", 3) && strncmp(n, "tty", 3) == 0) 173 n += 3; 174 if (strncmp(match, n, matchlen)) 175 continue; 176 debug1(" -> matched %s\n", match); 177 } 178 sprintf(SockPath + sdirlen, "/%s", name); 179 180 debug1("stat %s\n", SockPath); 181 errno = 0; 182 debug2("uid = %d, gid = %d\n", getuid(), getgid()); 183 debug2("euid = %d, egid = %d\n", geteuid(), getegid()); 184 if (stat(SockPath, &st)) 185 { 186 debug1("errno = %d\n", errno); 187 continue; 188 } 189 190#ifndef SOCK_NOT_IN_FS 191# ifdef NAMEDPIPE 192# ifdef S_ISFIFO 193 debug("S_ISFIFO?\n"); 194 if (!S_ISFIFO(st.st_mode)) 195 continue; 196# endif 197# else 198# ifdef S_ISSOCK 199 debug("S_ISSOCK?\n"); 200 if (!S_ISSOCK(st.st_mode)) 201 continue; 202# endif 203# endif 204#endif 205 206 debug2("st.st_uid = %d, real_uid = %d\n", st.st_uid, real_uid); 207 if ((int)st.st_uid != real_uid) 208 continue; 209 mode = (int)st.st_mode & 0777; 210 debug1(" has mode 0%03o\n", mode); 211#ifdef MULTIUSER 212 if (multi && ((mode & 0677) != 0601)) 213 { 214 debug(" is not a MULTI-USER session"); 215 if (strcmp(multi, LoginName)) 216 { 217 debug(" and we are in a foreign directory.\n"); 218 mode = -4; 219 } 220 else 221 { 222 debug(", but it is our own session.\n"); 223 } 224 } 225#endif 226 debug(" store it.\n"); 227 if ((sent = (struct sent *)malloc(sizeof(struct sent))) == 0) 228 continue; 229 sent->next = 0; 230 sent->name = SaveStr(name); 231 sent->mode = mode; 232 *slisttail = sent; 233 slisttail = &sent->next; 234 nfound++; 235 sockfd = MakeClientSocket(0); 236#ifdef USE_SETEUID 237 /* MakeClientSocket sets ids back to eff */ 238 xseteuid(real_uid); 239 xsetegid(real_gid); 240#endif 241 if (sockfd == -1) 242 { 243 debug2(" MakeClientSocket failed, unreachable? %d %d\n", 244 matchlen, wipeflag); 245 sent->mode = -3; 246#ifndef SOCKDIR_IS_LOCAL_TO_HOST 247 /* Unreachable - it is dead if we detect that it's local 248 * or we specified a match 249 */ 250 n = name + strlen(name) - 1; 251 while (n != name && *n != '.') 252 n--; 253 if (matchlen == 0 && !(*n == '.' && n[1] && strncmp(HostName, n + 1, strlen(n + 1)) == 0)) 254 { 255 npriv++; /* a good socket that was not for us */ 256 continue; 257 } 258#endif 259 ndead++; 260 sent->mode = -1; 261 if (wipeflag) 262 { 263 if (unlink(SockPath) == 0) 264 { 265 sent->mode = -2; 266 nwipe++; 267 } 268 } 269 continue; 270 } 271 272 mode &= 0776; 273 /* Shall we connect ? */ 274 debug2(" connecting: mode=%03o, rflag=%d, ", mode, rflag); 275 debug2("xflag=%d, dflag=%d ?\n", xflag, dflag); 276 277 /* 278 * mode 600: socket is detached. 279 * mode 700: socket is attached. 280 * xflag implies rflag here. 281 * 282 * fail, when socket mode mode is not 600 or 700 283 * fail, when we want to detach w/o reattach, but it already is detached. 284 * fail, when we only want to attach, but mode 700 and not xflag. 285 * fail, if none of dflag, rflag, xflag is set. 286 */ 287 if ((mode != 0700 && mode != 0600) || 288 (dflag && !rflag && !xflag && mode == 0600) || 289 (!dflag && rflag && mode == 0700 && !xflag) || 290 (!dflag && !rflag && !xflag)) 291 { 292 close(sockfd); 293 debug(" no!\n"); 294 npriv++; /* a good socket that was not for us */ 295 continue; 296 } 297 ngood++; 298 if (fdp && firsts == -1) 299 { 300 firsts = sockfd; 301 firstn = sent->name; 302 debug(" taken.\n"); 303 } 304 else 305 { 306 debug(" discarded.\n"); 307 close(sockfd); 308 } 309 } 310 (void)closedir(dirp); 311 if (nfound && (lsflag || ngood != 1) && !quietflag) 312 { 313 switch(ngood) 314 { 315 case 0: 316 Msg(0, nfound > 1 ? "There are screens on:" : "There is a screen on:"); 317 break; 318 case 1: 319 Msg(0, nfound > 1 ? "There are several screens on:" : "There is a suitable screen on:"); 320 break; 321 default: 322 Msg(0, "There are several suitable screens on:"); 323 break; 324 } 325 for (sent = slist; sent; sent = sent->next) 326 { 327 switch (sent->mode) 328 { 329 case 0700: 330 printf("\t%s\t(Attached)\n", sent->name); 331 break; 332 case 0600: 333 printf("\t%s\t(Detached)\n", sent->name); 334 break; 335#ifdef MULTIUSER 336 case 0701: 337 printf("\t%s\t(Multi, attached)\n", sent->name); 338 break; 339 case 0601: 340 printf("\t%s\t(Multi, detached)\n", sent->name); 341 break; 342#endif 343 case -1: 344 /* No trigraphs here! */ 345 printf("\t%s\t(Dead ?%c?)\n", sent->name, '?'); 346 break; 347 case -2: 348 printf("\t%s\t(Removed)\n", sent->name); 349 break; 350 case -3: 351 printf("\t%s\t(Remote or dead)\n", sent->name); 352 break; 353 case -4: 354 printf("\t%s\t(Private)\n", sent->name); 355 break; 356 } 357 } 358 } 359 if (ndead && !quietflag) 360 { 361 char *m = "Remove dead screens with 'screen -wipe'."; 362 if (wipeflag) 363 Msg(0, "%d socket%s wiped out.", nwipe, nwipe > 1 ? "s" : ""); 364 else 365 Msg(0, m, ndead > 1 ? "s" : "", ndead > 1 ? "" : "es"); /* other args for nethack */ 366 } 367 if (firsts != -1) 368 { 369 sprintf(SockPath + sdirlen, "/%s", firstn); 370 *fdp = firsts; 371 } 372 else 373 SockPath[sdirlen] = 0; 374 for (sent = slist; sent; sent = nsent) 375 { 376 nsent = sent->next; 377 free(sent->name); 378 free((char *)sent); 379 } 380#ifdef USE_SETEUID 381 xseteuid(eff_uid); 382 xsetegid(eff_gid); 383#endif 384 if (notherp) 385 *notherp = npriv; 386 if (nfoundp) 387 *nfoundp = nfound - nwipe; 388 return ngood; 389} 390 391 392/* 393** 394** Socket/pipe create routines 395** 396*/ 397 398#ifdef NAMEDPIPE 399 400int 401MakeServerSocket() 402{ 403 register int s; 404 struct stat st; 405 406# ifdef USE_SETEUID 407 xseteuid(real_uid); 408 xsetegid(real_gid); 409# endif 410 if ((s = open(SockPath, O_WRONLY | O_NONBLOCK)) >= 0) 411 { 412 debug("huii, my fifo already exists??\n"); 413 if (quietflag) 414 { 415 Kill(D_userpid, SIG_BYE); 416 eexit(11); 417 } 418 Msg(0, "There is already a screen running on %s.", Filename(SockPath)); 419 if (stat(SockPath, &st) == -1) 420 Panic(errno, "stat"); 421 if ((int)st.st_uid != real_uid) 422 Panic(0, "Unfortunatelly you are not its owner."); 423 if ((st.st_mode & 0700) == 0600) 424 Panic(0, "To resume it, use \"screen -r\""); 425 else 426 Panic(0, "It is not detached."); 427 /* NOTREACHED */ 428 } 429# ifdef USE_SETEUID 430 (void) unlink(SockPath); 431 if (mkfifo(SockPath, SOCKMODE)) 432 Panic(0, "mkfifo %s failed", SockPath); 433# ifdef BROKEN_PIPE 434 if ((s = open(SockPath, O_RDWR | O_NONBLOCK, 0)) < 0) 435# else 436 if ((s = open(SockPath, O_RDONLY | O_NONBLOCK, 0)) < 0) 437# endif 438 Panic(errno, "open fifo %s", SockPath); 439 xseteuid(eff_uid); 440 xsetegid(eff_gid); 441 return s; 442# else /* !USE_SETEUID */ 443 if (UserContext() > 0) 444 { 445 (void) unlink(SockPath); 446 UserReturn(mkfifo(SockPath, SOCKMODE)); 447 } 448 if (UserStatus()) 449 Panic(0, "mkfifo %s failed", SockPath); 450# ifdef BROKEN_PIPE 451 if ((s = secopen(SockPath, O_RDWR | O_NONBLOCK, 0)) < 0) 452# else 453 if ((s = secopen(SockPath, O_RDONLY | O_NONBLOCK, 0)) < 0) 454# endif 455 Panic(errno, "open fifo %s", SockPath); 456 return s; 457# endif /* !USE_SETEUID */ 458} 459 460 461int 462MakeClientSocket(err) 463int err; 464{ 465 register int s = 0; 466 467 if ((s = secopen(SockPath, O_WRONLY | O_NONBLOCK, 0)) >= 0) 468 { 469 (void) fcntl(s, F_SETFL, 0); 470 return s; 471 } 472 if (err) 473 Msg(errno, "%s", SockPath); 474 debug2("MakeClientSocket() open %s failed (%d)\n", SockPath, errno); 475 return -1; 476} 477 478 479#else /* NAMEDPIPE */ 480 481 482int 483MakeServerSocket() 484{ 485 register int s; 486 struct sockaddr_un a; 487 struct stat st; 488 489 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 490 Panic(errno, "socket"); 491 a.sun_family = AF_UNIX; 492 strncpy(a.sun_path, SockPath, sizeof(a.sun_path)); 493 a.sun_path[sizeof(a.sun_path) - 1] = 0; 494# ifdef USE_SETEUID 495 xseteuid(real_uid); 496 xsetegid(real_gid); 497# endif 498 if (connect(s, (struct sockaddr *) &a, strlen(SockPath) + 2) != -1) 499 { 500 debug("oooooh! socket already is alive!\n"); 501 if (quietflag) 502 { 503 Kill(D_userpid, SIG_BYE); 504 /* 505 * oh, well. nobody receives that return code. papa 506 * dies by signal. 507 */ 508 eexit(11); 509 } 510 Msg(0, "There is already a screen running on %s.", Filename(SockPath)); 511 if (stat(SockPath, &st) == -1) 512 Panic(errno, "stat"); 513 if (st.st_uid != real_uid) 514 Panic(0, "Unfortunatelly you are not its owner."); 515 if ((st.st_mode & 0700) == 0600) 516 Panic(0, "To resume it, use \"screen -r\""); 517 else 518 Panic(0, "It is not detached."); 519 /* NOTREACHED */ 520 } 521#if defined(m88k) || defined(sysV68) 522 close(s); /* we get bind: Invalid argument if this is not done */ 523 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 524 Panic(errno, "reopen socket"); 525#endif 526 (void) unlink(SockPath); 527 if (bind(s, (struct sockaddr *) & a, strlen(SockPath) + 2) == -1) 528 Panic(errno, "bind (%s)", SockPath); 529#ifdef SOCK_NOT_IN_FS 530 { 531 int f; 532 if ((f = secopen(SockPath, O_RDWR | O_CREAT, SOCKMODE)) < 0) 533 Panic(errno, "shadow socket open"); 534 close(f); 535 } 536#else 537 chmod(SockPath, SOCKMODE); 538# ifndef USE_SETEUID 539 chown(SockPath, real_uid, real_gid); 540# endif 541#endif /* SOCK_NOT_IN_FS */ 542 if (listen(s, 5) == -1) 543 Panic(errno, "listen"); 544# ifdef F_SETOWN 545 fcntl(s, F_SETOWN, getpid()); 546 debug1("Serversocket owned by %d\n", fcntl(s, F_GETOWN, 0)); 547# endif /* F_SETOWN */ 548# ifdef USE_SETEUID 549 xseteuid(eff_uid); 550 xsetegid(eff_gid); 551# endif 552 return s; 553} 554 555int 556MakeClientSocket(err) 557int err; 558{ 559 register int s; 560 struct sockaddr_un a; 561 562 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 563 Panic(errno, "socket"); 564 a.sun_family = AF_UNIX; 565 strncpy(a.sun_path, SockPath, sizeof(a.sun_path)); 566 a.sun_path[sizeof(a.sun_path) - 1] = 0; 567# ifdef USE_SETEUID 568 xseteuid(real_uid); 569 xsetegid(real_gid); 570# else 571 if (access(SockPath, W_OK)) 572 { 573 if (err) 574 Msg(errno, "%s", SockPath); 575 debug2("MakeClientSocket: access(%s): %d.\n", SockPath, errno); 576 close(s); 577 return -1; 578 } 579# endif 580 if (connect(s, (struct sockaddr *) &a, strlen(SockPath) + 2) == -1) 581 { 582 if (err) 583 Msg(errno, "%s: connect", SockPath); 584 debug("MakeClientSocket: connect failed.\n"); 585 close(s); 586 s = -1; 587 } 588# ifdef USE_SETEUID 589 xseteuid(eff_uid); 590 xsetegid(eff_gid); 591# endif 592 return s; 593} 594#endif /* NAMEDPIPE */ 595 596 597/* 598** 599** Message send and receive routines 600** 601*/ 602 603void 604SendCreateMsg(sty, nwin) 605char *sty; 606struct NewWindow *nwin; 607{ 608 int s; 609 struct msg m; 610 register char *p; 611 register int len, n; 612 char **av = nwin->args; 613 614#ifdef NAME_MAX 615 if (strlen(sty) > NAME_MAX) 616 sty[NAME_MAX] = 0; 617#endif 618 if (strlen(sty) > 2 * MAXSTR - 1) 619 sty[2 * MAXSTR - 1] = 0; 620 sprintf(SockPath + strlen(SockPath), "/%s", sty); 621 if ((s = MakeClientSocket(1)) == -1) 622 exit(1); 623 debug1("SendCreateMsg() to '%s'\n", SockPath); 624 bzero((char *)&m, sizeof(m)); 625 m.type = MSG_CREATE; 626 strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1); 627 m.m_tty[sizeof(m.m_tty) - 1] = 0; 628 p = m.m.create.line; 629 n = 0; 630 if (nwin->args != nwin_undef.args) 631 for (av = nwin->args; *av && n < MAXARGS - 1; ++av, ++n) 632 { 633 len = strlen(*av) + 1; 634 if (p + len >= m.m.create.line + sizeof(m.m.create.line) - 1) 635 break; 636 strcpy(p, *av); 637 p += len; 638 } 639 if (nwin->aka != nwin_undef.aka && p + strlen(nwin->aka) + 1 < m.m.create.line + sizeof(m.m.create.line)) 640 strcpy(p, nwin->aka); 641 else 642 *p = '\0'; 643 m.m.create.nargs = n; 644 m.m.create.aflag = nwin->aflag; 645 m.m.create.flowflag = nwin->flowflag; 646 m.m.create.lflag = nwin->lflag; 647 m.m.create.hheight = nwin->histheight; 648 if (getcwd(m.m.create.dir, sizeof(m.m.create.dir)) == 0) 649 { 650 Msg(errno, "getcwd"); 651 return; 652 } 653 if (nwin->term != nwin_undef.term) 654 strncpy(m.m.create.screenterm, nwin->term, 19); 655 m.m.create.screenterm[19] = '\0'; 656 m.protocol_revision = MSG_REVISION; 657 debug1("SendCreateMsg writing '%s'\n", m.m.create.line); 658 if (write(s, (char *) &m, sizeof m) != sizeof m) 659 Msg(errno, "write"); 660 close(s); 661} 662 663int 664SendErrorMsg(tty, buf) 665char *tty, *buf; 666{ 667 int s; 668 struct msg m; 669 670 strncpy(m.m.message, buf, sizeof(m.m.message) - 1); 671 m.m.message[sizeof(m.m.message) - 1] = 0; 672 s = MakeClientSocket(0); 673 if (s < 0) 674 return -1; 675 m.type = MSG_ERROR; 676 strncpy(m.m_tty, tty, sizeof(m.m_tty) - 1); 677 m.m_tty[sizeof(m.m_tty) - 1] = 0; 678 m.protocol_revision = MSG_REVISION; 679 debug1("SendErrorMsg(): writing to '%s'\n", SockPath); 680 (void) write(s, (char *) &m, sizeof m); 681 close(s); 682 return 0; 683} 684 685static void 686ExecCreate(mp) 687struct msg *mp; 688{ 689 struct NewWindow nwin; 690 char *args[MAXARGS]; 691 register int n; 692 register char **pp = args, *p = mp->m.create.line; 693 694 nwin = nwin_undef; 695 n = mp->m.create.nargs; 696 if (n > MAXARGS - 1) 697 n = MAXARGS - 1; 698 /* ugly hack alert... should be done by the frontend! */ 699 if (n) 700 { 701 int l, num; 702 char buf[20]; 703 704 l = strlen(p); 705 if (IsNumColon(p, 10, buf, sizeof(buf))) 706 { 707 if (*buf) 708 nwin.aka = buf; 709 num = atoi(p); 710 if (num < 0 || num > MAXWIN - 1) 711 num = 0; 712 nwin.StartAt = num; 713 p += l + 1; 714 n--; 715 } 716 } 717 for (; n > 0; n--) 718 { 719 *pp++ = p; 720 p += strlen(p) + 1; 721 } 722 *pp = 0; 723 if (*p) 724 nwin.aka = p; 725 if (*args) 726 nwin.args = args; 727 nwin.aflag = mp->m.create.aflag; 728 nwin.flowflag = mp->m.create.flowflag; 729 if (*mp->m.create.dir) 730 nwin.dir = mp->m.create.dir; 731 nwin.lflag = mp->m.create.lflag; 732 nwin.histheight = mp->m.create.hheight; 733 if (*mp->m.create.screenterm) 734 nwin.term = mp->m.create.screenterm; 735 MakeWindow(&nwin); 736} 737 738static int 739CheckPid(pid) 740int pid; 741{ 742 debug1("Checking pid %d\n", pid); 743 if (pid < 2) 744 return -1; 745 if (eff_uid == real_uid) 746 return kill(pid, 0); 747 if (UserContext() > 0) 748 UserReturn(kill(pid, 0)); 749 return UserStatus(); 750} 751 752#ifdef hpux 753/* 754 * From: "F. K. Bruner" <napalm@ugcs.caltech.edu> 755 * From: "Dan Egnor" <egnor@oracorp.com> Tue Aug 10 06:56:45 1993 756 * The problem is that under HPUX (and possibly other systems too) there are 757 * two equivalent device files for each pty/tty device: 758 * /dev/ttyxx == /dev/pty/ttyxx 759 * /dev/ptyxx == /dev/ptym/ptyxx 760 * I didn't look into the exact specifics, but I've run across this problem 761 * before: Even if you open /dev/ttyxx as fds 0 1 & 2 for a process, if that 762 * process calls the system to determine its tty, it'll get /dev/pty/ttyxx. 763 * 764 * Earlier versions seemed to work -- wonder what they did. 765 */ 766static int 767ttycmp(s1, s2) 768char *s1, *s2; 769{ 770 if (strlen(s1) > 5) s1 += strlen(s1) - 5; 771 if (strlen(s2) > 5) s2 += strlen(s2) - 5; 772 return strcmp(s1, s2); 773} 774# define TTYCMP(a, b) ttycmp(a, b) 775#else 776# define TTYCMP(a, b) strcmp(a, b) 777#endif 778 779void 780ReceiveMsg() 781{ 782 int left, len, i; 783 static struct msg m; 784 char *p; 785 int ns = ServerSocket; 786 struct mode Mode; 787 struct win *wi; 788#ifdef REMOTE_DETACH 789 struct display *next; 790#endif 791 struct display *olddisplays = displays; 792 793#ifdef NAMEDPIPE 794 debug("Ha, there was someone knocking on my fifo??\n"); 795 if (fcntl(ServerSocket, F_SETFL, 0) == -1) 796 Panic(errno, "BLOCK fcntl"); 797#else 798 struct sockaddr_un a; 799 800 len = sizeof(a); 801 debug("Ha, there was someone knocking on my socket??\n"); 802 if ((ns = accept(ns, (struct sockaddr *) &a, &len)) < 0) 803 { 804 Msg(errno, "accept"); 805 return; 806 } 807#endif /* NAMEDPIPE */ 808 809 p = (char *) &m; 810 left = sizeof(m); 811 while (left > 0) 812 { 813 len = read(ns, p, left); 814 if (len < 0 && errno == EINTR) 815 continue; 816 if (len <= 0) 817 break; 818 p += len; 819 left -= len; 820 } 821 822#ifdef NAMEDPIPE 823# ifndef BROKEN_PIPE 824 /* Reopen pipe to prevent EOFs at the select() call */ 825 close(ServerSocket); 826 if ((ServerSocket = secopen(SockPath, O_RDONLY | O_NONBLOCK, 0)) < 0) 827 Panic(errno, "reopen fifo %s", SockPath); 828 evdeq(&serv_read); 829 serv_read.fd = ServerSocket; 830 evenq(&serv_read); 831# endif 832#else 833 close(ns); 834#endif 835 836 if (len < 0) 837 { 838 Msg(errno, "read"); 839 return; 840 } 841 if (left > 0) 842 { 843 if (left != sizeof(m)) 844 Msg(0, "Message %d of %d bytes too small", left, (int)sizeof(m)); 845 else 846 debug("No data on socket.\n"); 847 return; 848 } 849 if (m.protocol_revision != MSG_REVISION) 850 { 851 Msg(0, "Invalid message (magic 0x%08x).", m.protocol_revision); 852 return; 853 } 854 855 debug2("*** RecMsg: type %d tty %s\n", m.type, m.m_tty); 856 for (display = displays; display; display = display->d_next) 857 if (TTYCMP(D_usertty, m.m_tty) == 0) 858 break; 859 debug2("display: %s display %sfound\n", m.m_tty, display ? "" : "not "); 860 wi = 0; 861 if (!display) 862 { 863 for (wi = windows; wi; wi = wi->w_next) 864 if (!TTYCMP(m.m_tty, wi->w_tty)) 865 { 866 /* XXX: hmmm, rework this? */ 867 display = wi->w_layer.l_cvlist ? wi->w_layer.l_cvlist->c_display : 0; 868 debug2("but window %s %sfound.\n", m.m_tty, display ? "" : 869 "(backfacing)"); 870 break; 871 } 872 } 873 874 /* Remove the status to prevent garbage on the screen */ 875 if (display && D_status) 876 RemoveStatus(); 877 878 if (display && !D_tcinited && m.type != MSG_HANGUP) 879 return; /* ignore messages for bad displays */ 880 881 switch (m.type) 882 { 883 case MSG_WINCH: 884 if (display) 885 CheckScreenSize(1); /* Change fore */ 886 break; 887 case MSG_CREATE: 888 /* 889 * the window that issued the create message need not be an active 890 * window. Then we create the window without having a display. 891 * Resulting in another inactive window. 892 * 893 * Currently we enforce that at least one display exists. But why? 894 * jw. 895 */ 896 if (displays) 897 ExecCreate(&m); 898 break; 899 case MSG_CONT: 900 if (display && D_userpid != 0 && kill(D_userpid, 0) == 0) 901 break; /* Intruder Alert */ 902 debug2("RecMsg: apid=%d,was %d\n", m.m.attach.apid, display ? D_userpid : 0); 903 /* FALLTHROUGH */ 904 905 case MSG_ATTACH: 906 if (CheckPid(m.m.attach.apid)) 907 { 908 Msg(0, "Attach attempt with bad pid(%d)!", m.m.attach.apid); 909 break; 910 } 911 if ((i = secopen(m.m_tty, O_RDWR | O_NONBLOCK, 0)) < 0) 912 { 913 Msg(errno, "Attach: Could not open %s!", m.m_tty); 914 Kill(m.m.attach.apid, SIG_BYE); 915 break; 916 } 917# ifdef MULTIUSER 918 Kill(m.m.attach.apid, SIGCONT); 919# endif 920 921#if defined(ultrix) || defined(pyr) || defined(NeXT) 922 brktty(i); /* for some strange reason this must be done */ 923#endif 924 925 if (display || wi) 926 { 927 write(i, "Attaching from inside of screen?\n", 33); 928 close(i); 929 Kill(m.m.attach.apid, SIG_BYE); 930 Msg(0, "Attach msg ignored: coming from inside."); 931 break; 932 } 933 934#ifdef MULTIUSER 935 if (strcmp(m.m.attach.auser, LoginName)) 936 if (*FindUserPtr(m.m.attach.auser) == 0) 937 { 938 write(i, "Access to session denied.\n", 26); 939 close(i); 940 Kill(m.m.attach.apid, SIG_BYE); 941 Msg(0, "Attach: access denied for user %s.", m.m.attach.auser); 942 break; 943 } 944#endif 945 946 debug2("RecMsg: apid %d is o.k. and we just opened '%s'\n", m.m.attach.apid, m.m_tty); 947#ifndef MULTI 948 if (displays) 949 { 950 write(i, "Screen session in use.\n", 23); 951 close(i); 952 Kill(m.m.attach.apid, SIG_BYE); 953 break; 954 } 955#endif 956 957 /* create new display */ 958 GetTTY(i, &Mode); 959 if (MakeDisplay(m.m.attach.auser, m.m_tty, m.m.attach.envterm, i, m.m.attach.apid, &Mode) == 0) 960 { 961 write(i, "Could not make display.\n", 24); 962 close(i); 963 Msg(0, "Attach: could not make display for user %s", m.m.attach.auser); 964 Kill(m.m.attach.apid, SIG_BYE); 965 break; 966 } 967#ifdef ENCODINGS 968# ifdef UTF8 969 D_encoding = m.m.attach.encoding == 1 ? UTF8 : m.m.attach.encoding ? m.m.attach.encoding - 1 : 0; 970# else 971 D_encoding = m.m.attach.encoding ? m.m.attach.encoding - 1 : 0; 972# endif 973 if (D_encoding < 0 || !EncodingName(D_encoding)) 974 D_encoding = 0; 975#endif 976 /* turn off iflag on a multi-attach... */ 977 if (iflag && olddisplays) 978 { 979 iflag = 0; 980#if defined(TERMIO) || defined(POSIX) 981 olddisplays->d_NewMode.tio.c_cc[VINTR] = VDISABLE; 982 olddisplays->d_NewMode.tio.c_lflag &= ~ISIG; 983#else /* TERMIO || POSIX */ 984 olddisplays->d_NewMode.m_tchars.t_intrc = -1; 985#endif /* TERMIO || POSIX */ 986 SetTTY(olddisplays->d_userfd, &olddisplays->d_NewMode); 987 } 988 SetMode(&D_OldMode, &D_NewMode, D_flow, iflag); 989 SetTTY(D_userfd, &D_NewMode); 990 if (fcntl(D_userfd, F_SETFL, FNBLOCK)) 991 Msg(errno, "Warning: NBLOCK fcntl failed"); 992 993#ifdef PASSWORD 994 if (D_user->u_password && *D_user->u_password) 995 AskPassword(&m); 996 else 997#endif 998 FinishAttach(&m); 999 break; 1000 case MSG_ERROR: 1001 Msg(0, "%s", m.m.message); 1002 break; 1003 case MSG_HANGUP: 1004 if (!wi) /* ignore hangups from inside */ 1005 Hangup(); 1006 break; 1007#ifdef REMOTE_DETACH 1008 case MSG_DETACH: 1009# ifdef POW_DETACH 1010 case MSG_POW_DETACH: 1011# endif /* POW_DETACH */ 1012 for (display = displays; display; display = next) 1013 { 1014 next = display->d_next; 1015# ifdef POW_DETACH 1016 if (m.type == MSG_POW_DETACH) 1017 Detach(D_REMOTE_POWER); 1018 else 1019# endif /* POW_DETACH */ 1020 if (m.type == MSG_DETACH) 1021 Detach(D_REMOTE); 1022 } 1023 break; 1024#endif 1025 case MSG_COMMAND: 1026 DoCommandMsg(&m); 1027 break; 1028 default: 1029 Msg(0, "Invalid message (type %d).", m.type); 1030 } 1031} 1032 1033#if defined(_SEQUENT_) && !defined(NAMEDPIPE) 1034#undef connect 1035/* 1036 * sequent_ptx socket emulation must have mode 000 on the socket! 1037 */ 1038static int 1039sconnect(s, sapp, len) 1040int s, len; 1041struct sockaddr *sapp; 1042{ 1043 register struct sockaddr_un *sap; 1044 struct stat st; 1045 int x; 1046 1047 sap = (struct sockaddr_un *)sapp; 1048 if (stat(sap->sun_path, &st)) 1049 return -1; 1050 chmod(sap->sun_path, 0); 1051 x = connect(s, (struct sockaddr *) sap, len); 1052 chmod(sap->sun_path, st.st_mode); 1053 return x; 1054} 1055#endif 1056 1057 1058/* 1059 * Set the mode bits of the socket to the current status 1060 */ 1061int 1062chsock() 1063{ 1064 int r, euid = geteuid(); 1065 if (euid != real_uid) 1066 { 1067 if (UserContext() <= 0) 1068 return UserStatus(); 1069 } 1070 r = chmod(SockPath, SOCKMODE); 1071 /* 1072 * Sockets usually reside in the /tmp/ area, where sysadmin scripts 1073 * may be happy to remove old files. We manually prevent the socket 1074 * from becoming old. (chmod does not touch mtime). 1075 */ 1076 (void)utimes(SockPath, NULL); 1077 1078 if (euid != real_uid) 1079 UserReturn(r); 1080 return r; 1081} 1082 1083/* 1084 * Try to recreate the socket/pipe 1085 */ 1086int 1087RecoverSocket() 1088{ 1089 close(ServerSocket); 1090 if ((int)geteuid() != real_uid) 1091 { 1092 if (UserContext() > 0) 1093 UserReturn(unlink(SockPath)); 1094 (void)UserStatus(); 1095 } 1096 else 1097 (void) unlink(SockPath); 1098 1099 if ((ServerSocket = MakeServerSocket()) < 0) 1100 return 0; 1101 evdeq(&serv_read); 1102 serv_read.fd = ServerSocket; 1103 evenq(&serv_read); 1104 return 1; 1105} 1106 1107 1108static void 1109FinishAttach(m) 1110struct msg *m; 1111{ 1112 char *p; 1113 int pid; 1114 int noshowwin; 1115 1116#ifndef __APPLE__ 1117 struct win *wi; 1118#endif 1119 1120 ASSERT(display); 1121 pid = D_userpid; 1122 1123#if defined(pyr) || defined(xelos) || defined(sequent) 1124 /* 1125 * Kludge for systems with braindamaged termcap routines, 1126 * which evaluate $TERMCAP, regardless weather it describes 1127 * the correct terminal type or not. 1128 */ 1129 debug("unsetenv(TERMCAP) in case of a different terminal"); 1130 unsetenv("TERMCAP"); 1131#endif 1132 1133 /* 1134 * We reboot our Terminal Emulator. Forget all we knew about 1135 * the old terminal, reread the termcap entries in .screenrc 1136 * (and nothing more from .screenrc is read. Mainly because 1137 * I did not check, weather a full reinit is safe. jw) 1138 * and /etc/screenrc, and initialise anew. 1139 */ 1140 if (extra_outcap) 1141 free(extra_outcap); 1142 if (extra_incap) 1143 free(extra_incap); 1144 extra_incap = extra_outcap = 0; 1145 debug2("Message says size (%dx%d)\n", m->m.attach.columns, m->m.attach.lines); 1146#ifdef ETCSCREENRC 1147# ifdef ALLOW_SYSSCREENRC 1148 if ((p = getenv("SYSSCREENRC"))) 1149 StartRc(p); 1150 else 1151# endif 1152 StartRc(ETCSCREENRC); 1153#endif 1154 StartRc(RcFileName); 1155 if (InitTermcap(m->m.attach.columns, m->m.attach.lines)) 1156 { 1157 FreeDisplay(); 1158 Kill(pid, SIG_BYE); 1159 return; 1160 } 1161 MakeDefaultCanvas(); 1162 InitTerm(m->m.attach.adaptflag); /* write init string on fd */ 1163 if (displays->d_next == 0) 1164 (void) chsock(); 1165 signal(SIGHUP, SigHup); 1166 if (m->m.attach.esc != -1 && m->m.attach.meta_esc != -1) 1167 { 1168 D_user->u_Esc = m->m.attach.esc; 1169 D_user->u_MetaEsc = m->m.attach.meta_esc; 1170 } 1171 1172#ifdef UTMPOK 1173 /* 1174 * we set the Utmp slots again, if we were detached normally 1175 * and if we were detached by ^Z. 1176 * don't log zomies back in! 1177 */ 1178 RemoveLoginSlot(); 1179 if (displays->d_next == 0) 1180 for (wi = windows; wi; wi = wi->w_next) 1181 if (wi->w_ptyfd >= 0 && wi->w_slot != (slot_t) -1) 1182 SetUtmp(wi); 1183#endif 1184 1185 D_fore = NULL; 1186 /* 1187 * there may be a window that we remember from last detach: 1188 */ 1189 debug1("D_user->u_detachwin = %d\n", D_user->u_detachwin); 1190 if (D_user->u_detachwin >= 0) 1191 fore = wtab[D_user->u_detachwin]; 1192 else 1193 fore = 0; 1194 1195 /* Wayne wants us to restore the other window too. */ 1196 if (D_user->u_detachotherwin >= 0) 1197 D_other = wtab[D_user->u_detachotherwin]; 1198 1199 noshowwin = 0; 1200 if (*m->m.attach.preselect) 1201 { 1202 if (!strcmp(m->m.attach.preselect, "=")) 1203 fore = 0; 1204 else if (!strcmp(m->m.attach.preselect, "-")) 1205 { 1206 fore = 0; 1207 noshowwin = 1; 1208 } 1209 else 1210 fore = FindNiceWindow(fore, m->m.attach.preselect); 1211 } 1212 else 1213 fore = FindNiceWindow(fore, 0); 1214 if (fore) 1215 SetForeWindow(fore); 1216 else if (!noshowwin) 1217 { 1218#ifdef MULTIUSER 1219 if (!AclCheckPermCmd(D_user, ACL_EXEC, &comms[RC_WINDOWLIST])) 1220#endif 1221 { 1222 flayer = D_forecv->c_layer; 1223 display_wlist(1, WLIST_NUM); 1224 noshowwin = 1; 1225 } 1226 } 1227 Activate(0); 1228 ResetIdle(); 1229 if (!D_fore && !noshowwin) 1230 ShowWindows(-1); 1231 if (displays->d_next == 0 && console_window) 1232 { 1233 if (TtyGrabConsole(console_window->w_ptyfd, 1, "reattach") == 0) 1234 Msg(0, "console %s is on window %d", HostName, console_window->w_number); 1235 } 1236 debug("activated...\n"); 1237 1238# if defined(DEBUG) && defined(SIG_NODEBUG) 1239 if (!dfp) 1240 { 1241 sleep(1); 1242 debug1("Attacher %d must not debug, as we have debug off.\n", pid); 1243 kill(pid, SIG_NODEBUG); 1244 } 1245# endif /* SIG_NODEBUG */ 1246} 1247 1248 1249#ifdef PASSWORD 1250static void PasswordProcessInput __P((char *, int)); 1251 1252struct pwdata { 1253 int l; 1254 char buf[20 + 1]; 1255 struct msg m; 1256}; 1257 1258static void 1259AskPassword(m) 1260struct msg *m; 1261{ 1262 struct pwdata *pwdata; 1263 ASSERT(display); 1264 pwdata = (struct pwdata *)malloc(sizeof(struct pwdata)); 1265 if (!pwdata) 1266 Panic(0, strnomem); 1267 pwdata->l = 0; 1268 pwdata->m = *m; 1269 D_processinputdata = (char *)pwdata; 1270 D_processinput = PasswordProcessInput; 1271 AddStr("Screen password: "); 1272} 1273 1274static void 1275PasswordProcessInput(ibuf, ilen) 1276char *ibuf; 1277int ilen; 1278{ 1279 struct pwdata *pwdata; 1280 int c, l; 1281 char *up; 1282 int pid = D_userpid; 1283 1284 pwdata = (struct pwdata *)D_processinputdata; 1285 l = pwdata->l; 1286 while (ilen-- > 0) 1287 { 1288 c = *(unsigned char *)ibuf++; 1289 if (c == '\r' || c == '\n') 1290 { 1291 up = D_user->u_password; 1292 pwdata->buf[l] = 0; 1293 if (strncmp(crypt(pwdata->buf, up), up, strlen(up))) 1294 { 1295 /* uh oh, user failed */ 1296 bzero(pwdata->buf, sizeof(pwdata->buf)); 1297 AddStr("\r\nPassword incorrect.\r\n"); 1298 D_processinputdata = 0; /* otherwise freed by FreeDis */ 1299 FreeDisplay(); 1300 Msg(0, "Illegal reattach attempt from terminal %s.", pwdata->m.m_tty); 1301 free(pwdata); 1302 Kill(pid, SIG_BYE); 1303 return; 1304 } 1305 /* great, pw matched, all is fine */ 1306 bzero(pwdata->buf, sizeof(pwdata->buf)); 1307 AddStr("\r\n"); 1308 D_processinputdata = 0; 1309 D_processinput = ProcessInput; 1310 FinishAttach(&pwdata->m); 1311 free(pwdata); 1312 return; 1313 } 1314 if (c == Ctrl('c')) 1315 { 1316 AddStr("\r\n"); 1317 FreeDisplay(); 1318 Kill(pid, SIG_BYE); 1319 return; 1320 } 1321 if (c == '\b' || c == 0177) 1322 { 1323 if (l > 0) 1324 l--; 1325 continue; 1326 } 1327 if (c == Ctrl('u')) 1328 { 1329 l = 0; 1330 continue; 1331 } 1332 if (l < (int)sizeof(pwdata->buf) - 1) 1333 pwdata->buf[l++] = c; 1334 } 1335 pwdata->l = l; 1336} 1337#endif 1338 1339static void 1340DoCommandMsg(mp) 1341struct msg *mp; 1342{ 1343 char *args[MAXARGS]; 1344 int argl[MAXARGS]; 1345 int n, *lp; 1346 register char **pp = args, *p = mp->m.command.cmd; 1347 struct acluser *user; 1348#ifdef MULTIUSER 1349 extern struct acluser *EffectiveAclUser; /* acls.c */ 1350#else 1351 extern struct acluser *users; /* acls.c */ 1352#endif 1353 1354 lp = argl; 1355 n = mp->m.command.nargs; 1356 if (n > MAXARGS - 1) 1357 n = MAXARGS - 1; 1358 for (; n > 0; n--) 1359 { 1360 *pp++ = p; 1361 *lp = strlen(p); 1362 p += *lp++ + 1; 1363 } 1364 *pp = 0; 1365#ifdef MULTIUSER 1366 user = *FindUserPtr(mp->m.attach.auser); 1367 if (user == 0) 1368 { 1369 Msg(0, "Unknown user %s tried to send a command!", mp->m.attach.auser); 1370 return; 1371 } 1372#else 1373 user = users; 1374#endif 1375#ifdef PASSWORD 1376 if (user->u_password && *user->u_password) 1377 { 1378 Msg(0, "User %s has a password, cannot use -X option.", mp->m.attach.auser); 1379 return; 1380 } 1381#endif 1382 if (!display) 1383 for (display = displays; display; display = display->d_next) 1384 if (D_user == user) 1385 break; 1386 for (fore = windows; fore; fore = fore->w_next) 1387 if (!TTYCMP(mp->m_tty, fore->w_tty)) 1388 { 1389 if (!display) 1390 display = fore->w_layer.l_cvlist ? fore->w_layer.l_cvlist->c_display : 0; 1391 break; 1392 } 1393 if (!display) 1394 display = displays; /* sigh */ 1395 if (*mp->m.command.preselect) 1396 { 1397 int i = -1; 1398 if (strcmp(mp->m.command.preselect, "-")) 1399 i = WindowByNoN(mp->m.command.preselect); 1400 fore = i >= 0 ? wtab[i] : 0; 1401 } 1402 else if (!fore) 1403 { 1404 if (display && D_user == user) 1405 fore = Layer2Window(display->d_forecv->c_layer); 1406 if (!fore) 1407 { 1408 fore = user->u_detachwin >= 0 ? wtab[user->u_detachwin] : 0; 1409 fore = FindNiceWindow(fore, 0); 1410 } 1411 } 1412#ifdef MULTIUSER 1413 EffectiveAclUser = user; 1414#endif 1415 if (*args) 1416 { 1417 char *oldrcname = rc_name; 1418 rc_name = "-X"; 1419 debug3("Running command on display %x window %x (%d)\n", display, fore, fore ? fore->w_number : -1); 1420 flayer = fore ? &fore->w_layer : 0; 1421 if (fore && fore->w_savelayer && (fore->w_blocked || fore->w_savelayer->l_cvlist == 0)) 1422 flayer = fore->w_savelayer; 1423 DoCommand(args, argl); 1424 rc_name = oldrcname; 1425 } 1426#ifdef MULTIUSER 1427 EffectiveAclUser = 0; 1428#endif 1429} 1430