Merge branch 'master' into lua-scripting
[screen-lua.git] / src / socket.c
blob48dd4955f013692862b39aaf6792c8ccbe6e2d31
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
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.
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.
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
21 ****************************************************************
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
33 #ifndef SIGINT
34 # include <signal.h>
35 #endif
37 #include "screen.h"
39 #ifdef HAVE_DIRENT_H
40 # include <dirent.h>
41 #else
42 # include <sys/dir.h>
43 # define dirent direct
44 #endif
46 #include "extern.h"
48 static int CheckPid __P((int));
49 static void ExecCreate __P((struct msg *));
50 static void DoCommandMsg __P((struct msg *));
51 #if defined(_SEQUENT_) && !defined(NAMEDPIPE)
52 # define connect sconnect /* _SEQUENT_ has braindamaged connect */
53 static int sconnect __P((int, struct sockaddr *, int));
54 #endif
55 static void FinishAttach __P((struct msg *));
56 static void AskPassword __P((struct msg *));
59 extern char *RcFileName, *extra_incap, *extra_outcap;
60 extern int ServerSocket, real_uid, real_gid, eff_uid, eff_gid;
61 extern int dflag, iflag, rflag, lsflag, quietflag, wipeflag, xflag;
62 extern char *attach_tty, *LoginName, HostName[];
63 extern struct display *display, *displays;
64 extern struct win *fore, *wtab[], *console_window, *windows;
65 extern struct layer *flayer;
66 extern struct layout *layout_attach, *layout_last, layout_last_marker;
67 extern struct NewWindow nwin_undef;
68 #ifdef MULTIUSER
69 extern char *multi;
70 #endif
72 extern char *getenv();
74 extern char SockPath[];
75 extern struct event serv_read;
76 extern char *rc_name;
77 extern struct comm comms[];
79 #ifdef MULTIUSER
80 # define SOCKMODE (S_IWRITE | S_IREAD | (displays ? S_IEXEC : 0) | (multi ? 1 : 0))
81 #else
82 # define SOCKMODE (S_IWRITE | S_IREAD | (displays ? S_IEXEC : 0))
83 #endif
87 * Socket directory manager
89 * fdp: pointer to store the first good socket.
90 * nfoundp: pointer to store the number of sockets found matching.
91 * notherp: pointer to store the number of sockets not matching.
92 * match: string to match socket name.
94 * The socket directory must be in SockPath!
95 * The global variables LoginName, multi, rflag, xflag, dflag,
96 * quietflag, SockPath are used.
98 * The first good socket is stored in fdp and its name is
99 * appended to SockPath.
100 * If none exists or fdp is NULL SockPath is not changed.
102 * Returns: number of good sockets.
107 FindSocket(fdp, nfoundp, notherp, match)
108 int *fdp;
109 int *nfoundp, *notherp;
110 char *match;
112 DIR *dirp;
113 struct dirent *dp;
114 struct stat st;
115 int mode;
116 int sdirlen;
117 int matchlen = 0;
118 char *name, *n;
119 int firsts = -1, sockfd;
120 char *firstn = NULL;
121 int nfound = 0, ngood = 0, ndead = 0, nwipe = 0, npriv = 0;
122 struct sent
124 struct sent *next;
125 int mode;
126 char *name;
127 } *slist, **slisttail, *sent, *nsent;
129 if (match)
131 matchlen = strlen(match);
132 #ifdef NAME_MAX
133 if (matchlen > NAME_MAX)
134 matchlen = NAME_MAX;
135 #endif
139 * SockPath contains the socket directory.
140 * At the end of FindSocket the socket name will be appended to it.
141 * Thus FindSocket() can only be called once!
143 sdirlen = strlen(SockPath);
145 #ifdef USE_SETEUID
146 xseteuid(real_uid);
147 xsetegid(real_gid);
148 #endif
150 if ((dirp = opendir(SockPath)) == 0)
151 Panic(errno, "Cannot opendir %s", SockPath);
153 slist = 0;
154 slisttail = &slist;
155 while ((dp = readdir(dirp)))
157 name = dp->d_name;
158 debug1("- %s\n", name);
159 if (*name == 0 || *name == '.' || strlen(name) > 2*MAXSTR)
160 continue;
161 if (matchlen)
163 n = name;
164 /* if we don't want to match digits. Skip them */
165 if ((*match <= '0' || *match > '9') && (*n > '0' && *n <= '9'))
167 while (*n >= '0' && *n <= '9')
168 n++;
169 if (*n == '.')
170 n++;
172 /* the tty prefix is optional */
173 if (strncmp(match, "tty", 3) && strncmp(n, "tty", 3) == 0)
174 n += 3;
175 if (strncmp(match, n, matchlen))
176 continue;
177 debug1(" -> matched %s\n", match);
179 sprintf(SockPath + sdirlen, "/%s", name);
181 debug1("stat %s\n", SockPath);
182 errno = 0;
183 debug2("uid = %d, gid = %d\n", getuid(), getgid());
184 debug2("euid = %d, egid = %d\n", geteuid(), getegid());
185 if (stat(SockPath, &st))
187 debug1("errno = %d\n", errno);
188 continue;
191 #ifndef SOCK_NOT_IN_FS
192 # ifdef NAMEDPIPE
193 # ifdef S_ISFIFO
194 debug("S_ISFIFO?\n");
195 if (!S_ISFIFO(st.st_mode))
196 continue;
197 # endif
198 # else
199 # ifdef S_ISSOCK
200 debug("S_ISSOCK?\n");
201 if (!S_ISSOCK(st.st_mode))
202 continue;
203 # endif
204 # endif
205 #endif
207 debug2("st.st_uid = %d, real_uid = %d\n", st.st_uid, real_uid);
208 if ((int)st.st_uid != real_uid)
209 continue;
210 mode = (int)st.st_mode & 0777;
211 debug1(" has mode 0%03o\n", mode);
212 #ifdef MULTIUSER
213 if (multi && ((mode & 0677) != 0601))
215 debug(" is not a MULTI-USER session");
216 if (strcmp(multi, LoginName))
218 debug(" and we are in a foreign directory.\n");
219 mode = -4;
221 else
223 debug(", but it is our own session.\n");
226 #endif
227 debug(" store it.\n");
228 if ((sent = (struct sent *)malloc(sizeof(struct sent))) == 0)
229 continue;
230 sent->next = 0;
231 sent->name = SaveStr(name);
232 sent->mode = mode;
233 *slisttail = sent;
234 slisttail = &sent->next;
235 nfound++;
236 sockfd = MakeClientSocket(0);
237 #ifdef USE_SETEUID
238 /* MakeClientSocket sets ids back to eff */
239 xseteuid(real_uid);
240 xsetegid(real_gid);
241 #endif
242 if (sockfd == -1)
244 debug2(" MakeClientSocket failed, unreachable? %d %d\n",
245 matchlen, wipeflag);
246 sent->mode = -3;
247 #ifndef SOCKDIR_IS_LOCAL_TO_HOST
248 /* Unreachable - it is dead if we detect that it's local
249 * or we specified a match
251 n = name + strlen(name) - 1;
252 while (n != name && *n != '.')
253 n--;
254 if (matchlen == 0 && !(*n == '.' && n[1] && strncmp(HostName, n + 1, strlen(n + 1)) == 0))
256 npriv++; /* a good socket that was not for us */
257 continue;
259 #endif
260 ndead++;
261 sent->mode = -1;
262 if (wipeflag)
264 if (unlink(SockPath) == 0)
266 sent->mode = -2;
267 nwipe++;
270 continue;
273 mode &= 0776;
274 /* Shall we connect ? */
275 debug2(" connecting: mode=%03o, rflag=%d, ", mode, rflag);
276 debug2("xflag=%d, dflag=%d ?\n", xflag, dflag);
279 * mode 600: socket is detached.
280 * mode 700: socket is attached.
281 * xflag implies rflag here.
283 * fail, when socket mode mode is not 600 or 700
284 * fail, when we want to detach w/o reattach, but it already is detached.
285 * fail, when we only want to attach, but mode 700 and not xflag.
286 * fail, if none of dflag, rflag, xflag is set.
288 if ((mode != 0700 && mode != 0600) ||
289 (dflag && !rflag && !xflag && mode == 0600) ||
290 (!dflag && rflag && mode == 0700 && !xflag) ||
291 (!dflag && !rflag && !xflag))
293 close(sockfd);
294 debug(" no!\n");
295 npriv++; /* a good socket that was not for us */
296 continue;
298 ngood++;
299 if (fdp && firsts == -1)
301 firsts = sockfd;
302 firstn = sent->name;
303 debug(" taken.\n");
305 else
307 debug(" discarded.\n");
308 close(sockfd);
311 (void)closedir(dirp);
312 if (nfound && (lsflag || ngood != 1) && !quietflag)
314 switch(ngood)
316 case 0:
317 Msg(0, nfound > 1 ? "There are screens on:" : "There is a screen on:");
318 break;
319 case 1:
320 Msg(0, nfound > 1 ? "There are several screens on:" : "There is a suitable screen on:");
321 break;
322 default:
323 Msg(0, "There are several suitable screens on:");
324 break;
326 for (sent = slist; sent; sent = sent->next)
328 switch (sent->mode)
330 case 0700:
331 printf("\t%s\t(Attached)\n", sent->name);
332 break;
333 case 0600:
334 printf("\t%s\t(Detached)\n", sent->name);
335 break;
336 #ifdef MULTIUSER
337 case 0701:
338 printf("\t%s\t(Multi, attached)\n", sent->name);
339 break;
340 case 0601:
341 printf("\t%s\t(Multi, detached)\n", sent->name);
342 break;
343 #endif
344 case -1:
345 /* No trigraphs here! */
346 printf("\t%s\t(Dead ?%c?)\n", sent->name, '?');
347 break;
348 case -2:
349 printf("\t%s\t(Removed)\n", sent->name);
350 break;
351 case -3:
352 printf("\t%s\t(Remote or dead)\n", sent->name);
353 break;
354 case -4:
355 printf("\t%s\t(Private)\n", sent->name);
356 break;
360 if (ndead && !quietflag)
362 char *m = "Remove dead screens with 'screen -wipe'.";
363 if (wipeflag)
364 Msg(0, "%d socket%s wiped out.", nwipe, nwipe > 1 ? "s" : "");
365 else
366 Msg(0, m, ndead > 1 ? "s" : "", ndead > 1 ? "" : "es"); /* other args for nethack */
368 if (firsts != -1)
370 sprintf(SockPath + sdirlen, "/%s", firstn);
371 *fdp = firsts;
373 else
374 SockPath[sdirlen] = 0;
375 for (sent = slist; sent; sent = nsent)
377 nsent = sent->next;
378 free(sent->name);
379 free((char *)sent);
381 #ifdef USE_SETEUID
382 xseteuid(eff_uid);
383 xsetegid(eff_gid);
384 #endif
385 if (notherp)
386 *notherp = npriv;
387 if (nfoundp)
388 *nfoundp = nfound - nwipe;
389 return ngood;
395 ** Socket/pipe create routines
399 #ifdef NAMEDPIPE
402 MakeServerSocket()
404 register int s;
405 struct stat st;
407 # ifdef USE_SETEUID
408 xseteuid(real_uid);
409 xsetegid(real_gid);
410 # endif
411 if ((s = open(SockPath, O_WRONLY | O_NONBLOCK)) >= 0)
413 debug("huii, my fifo already exists??\n");
414 if (quietflag)
416 Kill(D_userpid, SIG_BYE);
417 eexit(11);
419 Msg(0, "There is already a screen running on %s.", Filename(SockPath));
420 if (stat(SockPath, &st) == -1)
421 Panic(errno, "stat");
422 if ((int)st.st_uid != real_uid)
423 Panic(0, "Unfortunatelly you are not its owner.");
424 if ((st.st_mode & 0700) == 0600)
425 Panic(0, "To resume it, use \"screen -r\"");
426 else
427 Panic(0, "It is not detached.");
428 /* NOTREACHED */
430 # ifdef USE_SETEUID
431 (void) unlink(SockPath);
432 if (mkfifo(SockPath, SOCKMODE))
433 Panic(0, "mkfifo %s failed", SockPath);
434 # ifdef BROKEN_PIPE
435 if ((s = open(SockPath, O_RDWR | O_NONBLOCK, 0)) < 0)
436 # else
437 if ((s = open(SockPath, O_RDONLY | O_NONBLOCK, 0)) < 0)
438 # endif
439 Panic(errno, "open fifo %s", SockPath);
440 xseteuid(eff_uid);
441 xsetegid(eff_gid);
442 return s;
443 # else /* !USE_SETEUID */
444 if (UserContext() > 0)
446 (void) unlink(SockPath);
447 UserReturn(mkfifo(SockPath, SOCKMODE));
449 if (UserStatus())
450 Panic(0, "mkfifo %s failed", SockPath);
451 # ifdef BROKEN_PIPE
452 if ((s = secopen(SockPath, O_RDWR | O_NONBLOCK, 0)) < 0)
453 # else
454 if ((s = secopen(SockPath, O_RDONLY | O_NONBLOCK, 0)) < 0)
455 # endif
456 Panic(errno, "open fifo %s", SockPath);
457 return s;
458 # endif /* !USE_SETEUID */
463 MakeClientSocket(err)
464 int err;
466 register int s = 0;
468 if ((s = secopen(SockPath, O_WRONLY | O_NONBLOCK, 0)) >= 0)
470 (void) fcntl(s, F_SETFL, 0);
471 return s;
473 if (err)
474 Msg(errno, "%s", SockPath);
475 debug2("MakeClientSocket() open %s failed (%d)\n", SockPath, errno);
476 return -1;
480 #else /* NAMEDPIPE */
484 MakeServerSocket()
486 register int s;
487 struct sockaddr_un a;
488 struct stat st;
490 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
491 Panic(errno, "socket");
492 a.sun_family = AF_UNIX;
493 strncpy(a.sun_path, SockPath, sizeof(a.sun_path));
494 a.sun_path[sizeof(a.sun_path) - 1] = 0;
495 # ifdef USE_SETEUID
496 xseteuid(real_uid);
497 xsetegid(real_gid);
498 # endif
499 if (connect(s, (struct sockaddr *) &a, strlen(SockPath) + 2) != -1)
501 debug("oooooh! socket already is alive!\n");
502 if (quietflag)
504 Kill(D_userpid, SIG_BYE);
506 * oh, well. nobody receives that return code. papa
507 * dies by signal.
509 eexit(11);
511 Msg(0, "There is already a screen running on %s.", Filename(SockPath));
512 if (stat(SockPath, &st) == -1)
513 Panic(errno, "stat");
514 if (st.st_uid != real_uid)
515 Panic(0, "Unfortunatelly you are not its owner.");
516 if ((st.st_mode & 0700) == 0600)
517 Panic(0, "To resume it, use \"screen -r\"");
518 else
519 Panic(0, "It is not detached.");
520 /* NOTREACHED */
522 #if defined(m88k) || defined(sysV68)
523 close(s); /* we get bind: Invalid argument if this is not done */
524 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
525 Panic(errno, "reopen socket");
526 #endif
527 (void) unlink(SockPath);
528 if (bind(s, (struct sockaddr *) & a, strlen(SockPath) + 2) == -1)
529 Panic(errno, "bind (%s)", SockPath);
530 #ifdef SOCK_NOT_IN_FS
532 int f;
533 if ((f = secopen(SockPath, O_RDWR | O_CREAT, SOCKMODE)) < 0)
534 Panic(errno, "shadow socket open");
535 close(f);
537 #else
538 chmod(SockPath, SOCKMODE);
539 # ifndef USE_SETEUID
540 chown(SockPath, real_uid, real_gid);
541 # endif
542 #endif /* SOCK_NOT_IN_FS */
543 if (listen(s, 5) == -1)
544 Panic(errno, "listen");
545 # ifdef F_SETOWN
546 fcntl(s, F_SETOWN, getpid());
547 debug1("Serversocket owned by %d\n", fcntl(s, F_GETOWN, 0));
548 # endif /* F_SETOWN */
549 # ifdef USE_SETEUID
550 xseteuid(eff_uid);
551 xsetegid(eff_gid);
552 # endif
553 return s;
557 MakeClientSocket(err)
558 int err;
560 register int s;
561 struct sockaddr_un a;
563 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
564 Panic(errno, "socket");
565 a.sun_family = AF_UNIX;
566 strncpy(a.sun_path, SockPath, sizeof(a.sun_path));
567 a.sun_path[sizeof(a.sun_path) - 1] = 0;
568 # ifdef USE_SETEUID
569 xseteuid(real_uid);
570 xsetegid(real_gid);
571 # else
572 if (access(SockPath, W_OK))
574 if (err)
575 Msg(errno, "%s", SockPath);
576 debug2("MakeClientSocket: access(%s): %d.\n", SockPath, errno);
577 close(s);
578 return -1;
580 # endif
581 if (connect(s, (struct sockaddr *) &a, strlen(SockPath) + 2) == -1)
583 if (err)
584 Msg(errno, "%s: connect", SockPath);
585 debug("MakeClientSocket: connect failed.\n");
586 close(s);
587 s = -1;
589 # ifdef USE_SETEUID
590 xseteuid(eff_uid);
591 xsetegid(eff_gid);
592 # endif
593 return s;
595 #endif /* NAMEDPIPE */
600 ** Message send and receive routines
604 void
605 SendCreateMsg(sty, nwin)
606 char *sty;
607 struct NewWindow *nwin;
609 int s;
610 struct msg m;
611 register char *p;
612 register int len, n;
613 char **av = nwin->args;
615 #ifdef NAME_MAX
616 if (strlen(sty) > NAME_MAX)
617 sty[NAME_MAX] = 0;
618 #endif
619 if (strlen(sty) > 2 * MAXSTR - 1)
620 sty[2 * MAXSTR - 1] = 0;
621 sprintf(SockPath + strlen(SockPath), "/%s", sty);
622 if ((s = MakeClientSocket(1)) == -1)
623 exit(1);
624 debug1("SendCreateMsg() to '%s'\n", SockPath);
625 bzero((char *)&m, sizeof(m));
626 m.type = MSG_CREATE;
627 strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1);
628 m.m_tty[sizeof(m.m_tty) - 1] = 0;
629 p = m.m.create.line;
630 n = 0;
631 if (nwin->args != nwin_undef.args)
632 for (av = nwin->args; *av && n < MAXARGS - 1; ++av, ++n)
634 len = strlen(*av) + 1;
635 if (p + len >= m.m.create.line + sizeof(m.m.create.line) - 1)
636 break;
637 strcpy(p, *av);
638 p += len;
640 if (nwin->aka != nwin_undef.aka && p + strlen(nwin->aka) + 1 < m.m.create.line + sizeof(m.m.create.line))
641 strcpy(p, nwin->aka);
642 else
643 *p = '\0';
644 m.m.create.nargs = n;
645 m.m.create.aflag = nwin->aflag;
646 m.m.create.flowflag = nwin->flowflag;
647 m.m.create.lflag = nwin->lflag;
648 m.m.create.hheight = nwin->histheight;
649 if (getcwd(m.m.create.dir, sizeof(m.m.create.dir)) == 0)
651 Msg(errno, "getcwd");
652 return;
654 if (nwin->term != nwin_undef.term)
655 strncpy(m.m.create.screenterm, nwin->term, 19);
656 m.m.create.screenterm[19] = '\0';
657 m.protocol_revision = MSG_REVISION;
658 debug1("SendCreateMsg writing '%s'\n", m.m.create.line);
659 if (write(s, (char *) &m, sizeof m) != sizeof m)
660 Msg(errno, "write");
661 close(s);
665 SendErrorMsg(tty, buf)
666 char *tty, *buf;
668 int s;
669 struct msg m;
671 strncpy(m.m.message, buf, sizeof(m.m.message) - 1);
672 m.m.message[sizeof(m.m.message) - 1] = 0;
673 s = MakeClientSocket(0);
674 if (s < 0)
675 return -1;
676 m.type = MSG_ERROR;
677 strncpy(m.m_tty, tty, sizeof(m.m_tty) - 1);
678 m.m_tty[sizeof(m.m_tty) - 1] = 0;
679 m.protocol_revision = MSG_REVISION;
680 debug1("SendErrorMsg(): writing to '%s'\n", SockPath);
681 (void) write(s, (char *) &m, sizeof m);
682 close(s);
683 return 0;
686 static void
687 ExecCreate(mp)
688 struct msg *mp;
690 struct NewWindow nwin;
691 char *args[MAXARGS];
692 register int n;
693 register char **pp = args, *p = mp->m.create.line;
695 nwin = nwin_undef;
696 n = mp->m.create.nargs;
697 if (n > MAXARGS - 1)
698 n = MAXARGS - 1;
699 /* ugly hack alert... should be done by the frontend! */
700 if (n)
702 int l, num;
703 char buf[20];
705 l = strlen(p);
706 if (IsNumColon(p, 10, buf, sizeof(buf)))
708 if (*buf)
709 nwin.aka = buf;
710 num = atoi(p);
711 if (num < 0 || num > MAXWIN - 1)
712 num = 0;
713 nwin.StartAt = num;
714 p += l + 1;
715 n--;
718 for (; n > 0; n--)
720 *pp++ = p;
721 p += strlen(p) + 1;
723 *pp = 0;
724 if (*p)
725 nwin.aka = p;
726 if (*args)
727 nwin.args = args;
728 nwin.aflag = mp->m.create.aflag;
729 nwin.flowflag = mp->m.create.flowflag;
730 if (*mp->m.create.dir)
731 nwin.dir = mp->m.create.dir;
732 nwin.lflag = mp->m.create.lflag;
733 nwin.histheight = mp->m.create.hheight;
734 if (*mp->m.create.screenterm)
735 nwin.term = mp->m.create.screenterm;
736 MakeWindow(&nwin);
739 static int
740 CheckPid(pid)
741 int pid;
743 debug1("Checking pid %d\n", pid);
744 if (pid < 2)
745 return -1;
746 if (eff_uid == real_uid)
747 return kill(pid, 0);
748 if (UserContext() > 0)
749 UserReturn(kill(pid, 0));
750 return UserStatus();
753 #ifdef hpux
755 * From: "F. K. Bruner" <napalm@ugcs.caltech.edu>
756 * From: "Dan Egnor" <egnor@oracorp.com> Tue Aug 10 06:56:45 1993
757 * The problem is that under HPUX (and possibly other systems too) there are
758 * two equivalent device files for each pty/tty device:
759 * /dev/ttyxx == /dev/pty/ttyxx
760 * /dev/ptyxx == /dev/ptym/ptyxx
761 * I didn't look into the exact specifics, but I've run across this problem
762 * before: Even if you open /dev/ttyxx as fds 0 1 & 2 for a process, if that
763 * process calls the system to determine its tty, it'll get /dev/pty/ttyxx.
765 * Earlier versions seemed to work -- wonder what they did.
767 static int
768 ttycmp(s1, s2)
769 char *s1, *s2;
771 if (strlen(s1) > 5) s1 += strlen(s1) - 5;
772 if (strlen(s2) > 5) s2 += strlen(s2) - 5;
773 return strcmp(s1, s2);
775 # define TTYCMP(a, b) ttycmp(a, b)
776 #else
777 # define TTYCMP(a, b) strcmp(a, b)
778 #endif
780 void
781 ReceiveMsg()
783 int left, len, i;
784 static struct msg m;
785 char *p;
786 int ns = ServerSocket;
787 struct mode Mode;
788 struct win *wi;
789 #ifdef REMOTE_DETACH
790 struct display *next;
791 #endif
792 struct display *olddisplays = displays;
793 int recvfd = -1;
795 #ifdef NAMEDPIPE
796 debug("Ha, there was someone knocking on my fifo??\n");
797 if (fcntl(ServerSocket, F_SETFL, 0) == -1)
798 Panic(errno, "BLOCK fcntl");
799 p = (char *) &m;
800 left = sizeof(m);
801 #else
802 struct sockaddr_un a;
803 struct msghdr msg;
804 struct iovec iov;
805 char control[1024];
807 len = sizeof(a);
808 debug("Ha, there was someone knocking on my socket??\n");
809 if ((ns = accept(ns, (struct sockaddr *) &a, (void *)&len)) < 0)
811 Msg(errno, "accept");
812 return;
815 p = (char *) &m;
816 left = sizeof(m);
817 bzero(&msg, sizeof(msg));
818 iov.iov_base = &m;
819 iov.iov_len = left;
820 msg.msg_iov = &iov;
821 msg.msg_iovlen = 1;
822 msg.msg_controllen = sizeof(control);
823 msg.msg_control = &control;
824 while (left > 0)
826 len = recvmsg(ns, &msg, 0);
827 if (len < 0 && errno == EINTR)
828 continue;
829 if (len < 0)
831 close(ns);
832 Msg(errno, "read");
833 return;
835 if (msg.msg_controllen)
837 struct cmsghdr *cmsg;
838 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
840 int cl;
841 char *cp;
842 if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS)
843 continue;
844 cp = (char *)CMSG_DATA(cmsg);
845 cl = cmsg->cmsg_len;
846 while(cl >= CMSG_LEN(sizeof(int)))
848 int passedfd;
849 bcopy(cp, &passedfd, sizeof(int));
850 if (recvfd >= 0 && passedfd != recv)
851 close(recvfd);
852 recvfd = passedfd;
853 cl -= CMSG_LEN(sizeof(int));
857 p += len;
858 left -= len;
859 break;
862 #endif
864 while (left > 0)
866 len = read(ns, p, left);
867 if (len < 0 && errno == EINTR)
868 continue;
869 if (len <= 0)
870 break;
871 p += len;
872 left -= len;
875 #ifdef NAMEDPIPE
876 # ifndef BROKEN_PIPE
877 /* Reopen pipe to prevent EOFs at the select() call */
878 close(ServerSocket);
879 if ((ServerSocket = secopen(SockPath, O_RDONLY | O_NONBLOCK, 0)) < 0)
880 Panic(errno, "reopen fifo %s", SockPath);
881 evdeq(&serv_read);
882 serv_read.fd = ServerSocket;
883 evenq(&serv_read);
884 # endif
885 #else
886 close(ns);
887 #endif
889 if (len < 0)
891 Msg(errno, "read");
892 if (recvfd != -1)
893 close(recvfd);
894 return;
896 if (left > 0)
898 if (left != sizeof(m))
899 Msg(0, "Message %d of %d bytes too small", left, (int)sizeof(m));
900 else
901 debug("No data on socket.\n");
902 return;
904 if (m.protocol_revision != MSG_REVISION)
906 if (recvfd != -1)
907 close(recvfd);
908 Msg(0, "Invalid message (magic 0x%08x).", m.protocol_revision);
909 return;
912 debug2("*** RecMsg: type %d tty %s\n", m.type, m.m_tty);
913 if (m.type != MSG_ATTACH && recvfd != -1)
915 close(recvfd);
916 recvfd = -1;
919 for (display = displays; display; display = display->d_next)
920 if (TTYCMP(D_usertty, m.m_tty) == 0)
921 break;
922 debug2("display: %s display %sfound\n", m.m_tty, display ? "" : "not ");
923 wi = 0;
924 if (!display)
926 for (wi = windows; wi; wi = wi->w_next)
927 if (!TTYCMP(m.m_tty, wi->w_tty))
929 /* XXX: hmmm, rework this? */
930 display = wi->w_layer.l_cvlist ? wi->w_layer.l_cvlist->c_display : 0;
931 debug2("but window %s %sfound.\n", m.m_tty, display ? "" :
932 "(backfacing)");
933 break;
937 /* Remove the status to prevent garbage on the screen */
938 if (display && D_status)
939 RemoveStatus();
941 if (display && !D_tcinited && m.type != MSG_HANGUP)
943 if (recvfd != -1)
944 close(recvfd);
945 return; /* ignore messages for bad displays */
948 switch (m.type)
950 case MSG_WINCH:
951 if (display)
952 CheckScreenSize(1); /* Change fore */
953 break;
954 case MSG_CREATE:
956 * the window that issued the create message need not be an active
957 * window. Then we create the window without having a display.
958 * Resulting in another inactive window.
960 * Currently we enforce that at least one display exists. But why?
961 * jw.
963 if (displays)
964 ExecCreate(&m);
965 break;
966 case MSG_CONT:
967 if (display && D_userpid != 0 && kill(D_userpid, 0) == 0)
968 break; /* Intruder Alert */
969 debug2("RecMsg: apid=%d,was %d\n", m.m.attach.apid, display ? D_userpid : 0);
970 /* FALLTHROUGH */
972 case MSG_ATTACH:
973 if (CheckPid(m.m.attach.apid))
975 Msg(0, "Attach attempt with bad pid(%d)!", m.m.attach.apid);
976 break;
978 if (recvfd != -1)
980 char *myttyname;
981 i = recvfd;
982 recvfd = -1;
983 myttyname = ttyname(i);
984 if (myttyname == 0 || strcmp(myttyname, m.m_tty))
986 Msg(errno, "Attach: passed fd does not match tty: %s - %s!", m.m_tty, myttyname ? myttyname : "NULL");
987 close(i);
988 Kill(m.m.attach.apid, SIG_BYE);
989 break;
992 else if ((i = secopen(m.m_tty, O_RDWR | O_NONBLOCK, 0)) < 0)
994 Msg(errno, "Attach: Could not open %s!", m.m_tty);
995 Kill(m.m.attach.apid, SIG_BYE);
996 break;
998 # ifdef MULTIUSER
999 Kill(m.m.attach.apid, SIGCONT);
1000 # endif
1002 #if defined(ultrix) || defined(pyr) || defined(NeXT)
1003 brktty(i); /* for some strange reason this must be done */
1004 #endif
1006 if (display || wi)
1008 write(i, "Attaching from inside of screen?\n", 33);
1009 close(i);
1010 Kill(m.m.attach.apid, SIG_BYE);
1011 Msg(0, "Attach msg ignored: coming from inside.");
1012 break;
1015 #ifdef MULTIUSER
1016 if (strcmp(m.m.attach.auser, LoginName))
1017 if (*FindUserPtr(m.m.attach.auser) == 0)
1019 write(i, "Access to session denied.\n", 26);
1020 close(i);
1021 Kill(m.m.attach.apid, SIG_BYE);
1022 Msg(0, "Attach: access denied for user %s.", m.m.attach.auser);
1023 break;
1025 #endif
1027 debug2("RecMsg: apid %d is o.k. and we just opened '%s'\n", m.m.attach.apid, m.m_tty);
1028 #ifndef MULTI
1029 if (displays)
1031 write(i, "Screen session in use.\n", 23);
1032 close(i);
1033 Kill(m.m.attach.apid, SIG_BYE);
1034 break;
1036 #endif
1038 /* create new display */
1039 GetTTY(i, &Mode);
1040 if (MakeDisplay(m.m.attach.auser, m.m_tty, m.m.attach.envterm, i, m.m.attach.apid, &Mode) == 0)
1042 write(i, "Could not make display.\n", 24);
1043 close(i);
1044 Msg(0, "Attach: could not make display for user %s", m.m.attach.auser);
1045 Kill(m.m.attach.apid, SIG_BYE);
1046 break;
1048 #ifdef ENCODINGS
1049 # ifdef UTF8
1050 D_encoding = m.m.attach.encoding == 1 ? UTF8 : m.m.attach.encoding ? m.m.attach.encoding - 1 : 0;
1051 # else
1052 D_encoding = m.m.attach.encoding ? m.m.attach.encoding - 1 : 0;
1053 # endif
1054 if (D_encoding < 0 || !EncodingName(D_encoding))
1055 D_encoding = 0;
1056 #endif
1057 /* turn off iflag on a multi-attach... */
1058 if (iflag && olddisplays)
1060 iflag = 0;
1061 #if defined(TERMIO) || defined(POSIX)
1062 olddisplays->d_NewMode.tio.c_cc[VINTR] = VDISABLE;
1063 olddisplays->d_NewMode.tio.c_lflag &= ~ISIG;
1064 #else /* TERMIO || POSIX */
1065 olddisplays->d_NewMode.m_tchars.t_intrc = -1;
1066 #endif /* TERMIO || POSIX */
1067 SetTTY(olddisplays->d_userfd, &olddisplays->d_NewMode);
1069 SetMode(&D_OldMode, &D_NewMode, D_flow, iflag);
1070 SetTTY(D_userfd, &D_NewMode);
1071 if (fcntl(D_userfd, F_SETFL, FNBLOCK))
1072 Msg(errno, "Warning: NBLOCK fcntl failed");
1074 #ifdef PASSWORD
1075 if (D_user->u_password && *D_user->u_password)
1076 AskPassword(&m);
1077 else
1078 #endif
1079 FinishAttach(&m);
1080 break;
1081 case MSG_ERROR:
1082 Msg(0, "%s", m.m.message);
1083 break;
1084 case MSG_HANGUP:
1085 if (!wi) /* ignore hangups from inside */
1086 Hangup();
1087 break;
1088 #ifdef REMOTE_DETACH
1089 case MSG_DETACH:
1090 # ifdef POW_DETACH
1091 case MSG_POW_DETACH:
1092 # endif /* POW_DETACH */
1093 for (display = displays; display; display = next)
1095 next = display->d_next;
1096 # ifdef POW_DETACH
1097 if (m.type == MSG_POW_DETACH)
1098 Detach(D_REMOTE_POWER);
1099 else
1100 # endif /* POW_DETACH */
1101 if (m.type == MSG_DETACH)
1102 Detach(D_REMOTE);
1104 break;
1105 #endif
1106 case MSG_COMMAND:
1107 DoCommandMsg(&m);
1108 break;
1109 default:
1110 Msg(0, "Invalid message (type %d).", m.type);
1114 #if defined(_SEQUENT_) && !defined(NAMEDPIPE)
1115 #undef connect
1117 * sequent_ptx socket emulation must have mode 000 on the socket!
1119 static int
1120 sconnect(s, sapp, len)
1121 int s, len;
1122 struct sockaddr *sapp;
1124 register struct sockaddr_un *sap;
1125 struct stat st;
1126 int x;
1128 sap = (struct sockaddr_un *)sapp;
1129 if (stat(sap->sun_path, &st))
1130 return -1;
1131 chmod(sap->sun_path, 0);
1132 x = connect(s, (struct sockaddr *) sap, len);
1133 chmod(sap->sun_path, st.st_mode);
1134 return x;
1136 #endif
1140 * Set the mode bits of the socket to the current status
1143 chsock()
1145 int r, euid = geteuid();
1146 if (euid != real_uid)
1148 if (UserContext() <= 0)
1149 return UserStatus();
1151 r = chmod(SockPath, SOCKMODE);
1153 * Sockets usually reside in the /tmp/ area, where sysadmin scripts
1154 * may be happy to remove old files. We manually prevent the socket
1155 * from becoming old. (chmod does not touch mtime).
1157 (void)utimes(SockPath, NULL);
1159 if (euid != real_uid)
1160 UserReturn(r);
1161 return r;
1165 * Try to recreate the socket/pipe
1168 RecoverSocket()
1170 close(ServerSocket);
1171 if ((int)geteuid() != real_uid)
1173 if (UserContext() > 0)
1174 UserReturn(unlink(SockPath));
1175 (void)UserStatus();
1177 else
1178 (void) unlink(SockPath);
1180 if ((ServerSocket = MakeServerSocket()) < 0)
1181 return 0;
1182 evdeq(&serv_read);
1183 serv_read.fd = ServerSocket;
1184 evenq(&serv_read);
1185 return 1;
1189 static void
1190 FinishAttach(m)
1191 struct msg *m;
1193 char *p;
1194 int pid;
1195 int noshowwin;
1196 int r = 0;
1197 struct win *wi;
1199 ASSERT(display);
1200 pid = D_userpid;
1202 #if defined(pyr) || defined(xelos) || defined(sequent)
1204 * Kludge for systems with braindamaged termcap routines,
1205 * which evaluate $TERMCAP, regardless weather it describes
1206 * the correct terminal type or not.
1208 debug("unsetenv(TERMCAP) in case of a different terminal");
1209 unsetenv("TERMCAP");
1210 #endif
1213 * We reboot our Terminal Emulator. Forget all we knew about
1214 * the old terminal, reread the termcap entries in .screenrc
1215 * (and nothing more from .screenrc is read. Mainly because
1216 * I did not check, weather a full reinit is safe. jw)
1217 * and /etc/screenrc, and initialise anew.
1219 if (extra_outcap)
1220 free(extra_outcap);
1221 if (extra_incap)
1222 free(extra_incap);
1223 extra_incap = extra_outcap = 0;
1224 debug2("Message says size (%dx%d)\n", m->m.attach.columns, m->m.attach.lines);
1225 #ifdef ETCSCREENRC
1226 # ifdef ALLOW_SYSSCREENRC
1227 if ((p = getenv("SYSSCREENRC")))
1228 StartRc(p, 1);
1229 else
1230 # endif
1231 StartRc(ETCSCREENRC, 1);
1232 #endif
1233 StartRc(RcFileName, 1);
1234 if (InitTermcap(m->m.attach.columns, m->m.attach.lines))
1236 FreeDisplay();
1237 Kill(pid, SIG_BYE);
1238 return;
1240 MakeDefaultCanvas();
1241 InitTerm(m->m.attach.adaptflag); /* write init string on fd */
1242 if (displays->d_next == 0)
1243 (void) chsock();
1244 signal(SIGHUP, SigHup);
1245 if (m->m.attach.esc != -1 && m->m.attach.meta_esc != -1)
1247 D_user->u_Esc = m->m.attach.esc;
1248 D_user->u_MetaEsc = m->m.attach.meta_esc;
1251 #ifdef UTMPOK
1253 * we set the Utmp slots again, if we were detached normally
1254 * and if we were detached by ^Z.
1255 * don't log zomies back in!
1257 RemoveLoginSlot();
1258 if (displays->d_next == 0)
1259 for (wi = windows; wi; wi = wi->w_next)
1260 if (wi->w_ptyfd >= 0 && wi->w_slot != (slot_t) -1)
1261 SetUtmp(wi);
1262 #endif
1264 D_fore = NULL;
1265 if (layout_attach)
1267 struct layout *lay = layout_attach;
1268 if (lay == &layout_last_marker)
1269 lay = layout_last;
1270 if (lay)
1272 LoadLayout(lay, &D_canvas);
1273 SetCanvasWindow(D_forecv, 0);
1277 * there may be a window that we remember from last detach:
1279 debug1("D_user->u_detachwin = %d\n", D_user->u_detachwin);
1280 if (D_user->u_detachwin >= 0)
1281 fore = wtab[D_user->u_detachwin];
1282 else
1283 fore = 0;
1285 /* Wayne wants us to restore the other window too. */
1286 if (D_user->u_detachotherwin >= 0)
1287 D_other = wtab[D_user->u_detachotherwin];
1289 noshowwin = 0;
1290 if (*m->m.attach.preselect)
1292 if (!strcmp(m->m.attach.preselect, "="))
1293 fore = 0;
1294 else if (!strcmp(m->m.attach.preselect, "-"))
1296 fore = 0;
1297 noshowwin = 1;
1299 else if (!strcmp(m->m.attach.preselect, "+"))
1301 struct action newscreen;
1302 char *na = 0;
1303 newscreen.nr = RC_SCREEN;
1304 newscreen.args = &na;
1305 DoAction(&newscreen, -1);
1307 else
1308 fore = FindNiceWindow(fore, m->m.attach.preselect);
1310 else
1311 fore = FindNiceWindow(fore, 0);
1312 if (fore)
1313 SetForeWindow(fore);
1314 else if (!noshowwin)
1316 #ifdef MULTIUSER
1317 if (!AclCheckPermCmd(D_user, ACL_EXEC, &comms[RC_WINDOWLIST]))
1318 #endif
1320 flayer = D_forecv->c_layer;
1321 display_wlist(1, WLIST_NUM, (struct win *)0);
1322 noshowwin = 1;
1325 Activate(0);
1326 ResetIdle();
1327 if (!D_fore && !noshowwin)
1328 ShowWindows(-1);
1329 if (displays->d_next == 0 && console_window)
1331 if (TtyGrabConsole(console_window->w_ptyfd, 1, "reattach") == 0)
1332 Msg(0, "console %s is on window %d", HostName, console_window->w_number);
1334 debug("activated...\n");
1336 # if defined(DEBUG) && defined(SIG_NODEBUG)
1337 if (!dfp)
1339 sleep(1);
1340 debug1("Attacher %d must not debug, as we have debug off.\n", pid);
1341 kill(pid, SIG_NODEBUG);
1343 # endif /* SIG_NODEBUG */
1347 #ifdef PASSWORD
1348 static void PasswordProcessInput __P((char *, int));
1350 struct pwdata {
1351 int l;
1352 char buf[20 + 1];
1353 struct msg m;
1356 static void
1357 AskPassword(m)
1358 struct msg *m;
1360 struct pwdata *pwdata;
1361 ASSERT(display);
1362 pwdata = (struct pwdata *)malloc(sizeof(struct pwdata));
1363 if (!pwdata)
1364 Panic(0, strnomem);
1365 pwdata->l = 0;
1366 pwdata->m = *m;
1367 D_processinputdata = (char *)pwdata;
1368 D_processinput = PasswordProcessInput;
1369 AddStr("Screen password: ");
1372 static void
1373 PasswordProcessInput(ibuf, ilen)
1374 char *ibuf;
1375 int ilen;
1377 struct pwdata *pwdata;
1378 int c, l;
1379 char *up;
1380 int pid = D_userpid;
1382 pwdata = (struct pwdata *)D_processinputdata;
1383 l = pwdata->l;
1384 while (ilen-- > 0)
1386 c = *(unsigned char *)ibuf++;
1387 if (c == '\r' || c == '\n')
1389 up = D_user->u_password;
1390 pwdata->buf[l] = 0;
1391 if (strncmp(crypt(pwdata->buf, up), up, strlen(up)))
1393 /* uh oh, user failed */
1394 bzero(pwdata->buf, sizeof(pwdata->buf));
1395 AddStr("\r\nPassword incorrect.\r\n");
1396 D_processinputdata = 0; /* otherwise freed by FreeDis */
1397 FreeDisplay();
1398 Msg(0, "Illegal reattach attempt from terminal %s.", pwdata->m.m_tty);
1399 free(pwdata);
1400 Kill(pid, SIG_BYE);
1401 return;
1403 /* great, pw matched, all is fine */
1404 bzero(pwdata->buf, sizeof(pwdata->buf));
1405 AddStr("\r\n");
1406 D_processinputdata = 0;
1407 D_processinput = ProcessInput;
1408 FinishAttach(&pwdata->m);
1409 free(pwdata);
1410 return;
1412 if (c == Ctrl('c'))
1414 AddStr("\r\n");
1415 FreeDisplay();
1416 Kill(pid, SIG_BYE);
1417 return;
1419 if (c == '\b' || c == 0177)
1421 if (l > 0)
1422 l--;
1423 continue;
1425 if (c == Ctrl('u'))
1427 l = 0;
1428 continue;
1430 if (l < (int)sizeof(pwdata->buf) - 1)
1431 pwdata->buf[l++] = c;
1433 pwdata->l = l;
1435 #endif
1437 static void
1438 DoCommandMsg(mp)
1439 struct msg *mp;
1441 char *args[MAXARGS];
1442 int argl[MAXARGS];
1443 int n, *lp;
1444 register char **pp = args, *p = mp->m.command.cmd;
1445 struct acluser *user;
1446 #ifdef MULTIUSER
1447 extern struct acluser *EffectiveAclUser; /* acls.c */
1448 #else
1449 extern struct acluser *users; /* acls.c */
1450 #endif
1452 lp = argl;
1453 n = mp->m.command.nargs;
1454 if (n > MAXARGS - 1)
1455 n = MAXARGS - 1;
1456 for (; n > 0; n--)
1458 *pp++ = p;
1459 *lp = strlen(p);
1460 p += *lp++ + 1;
1462 *pp = 0;
1463 #ifdef MULTIUSER
1464 user = *FindUserPtr(mp->m.attach.auser);
1465 if (user == 0)
1467 Msg(0, "Unknown user %s tried to send a command!", mp->m.attach.auser);
1468 return;
1470 #else
1471 user = users;
1472 #endif
1473 #ifdef PASSWORD
1474 if (user->u_password && *user->u_password)
1476 Msg(0, "User %s has a password, cannot use -X option.", mp->m.attach.auser);
1477 return;
1479 #endif
1480 if (!display)
1481 for (display = displays; display; display = display->d_next)
1482 if (D_user == user)
1483 break;
1484 for (fore = windows; fore; fore = fore->w_next)
1485 if (!TTYCMP(mp->m_tty, fore->w_tty))
1487 if (!display)
1488 display = fore->w_layer.l_cvlist ? fore->w_layer.l_cvlist->c_display : 0;
1489 break;
1491 if (!display)
1492 display = displays; /* sigh */
1493 if (*mp->m.command.preselect)
1495 int i = -1;
1496 if (strcmp(mp->m.command.preselect, "-"))
1497 i = WindowByNoN(mp->m.command.preselect);
1498 fore = i >= 0 ? wtab[i] : 0;
1500 else if (!fore)
1502 if (display && D_user == user)
1503 fore = Layer2Window(display->d_forecv->c_layer);
1504 if (!fore)
1506 fore = user->u_detachwin >= 0 ? wtab[user->u_detachwin] : 0;
1507 fore = FindNiceWindow(fore, 0);
1510 #ifdef MULTIUSER
1511 EffectiveAclUser = user;
1512 #endif
1513 if (*args)
1515 char *oldrcname = rc_name;
1516 rc_name = "-X";
1517 debug3("Running command on display %x window %x (%d)\n", display, fore, fore ? fore->w_number : -1);
1518 flayer = fore ? &fore->w_layer : 0;
1519 if (fore && fore->w_savelayer && (fore->w_blocked || fore->w_savelayer->l_cvlist == 0))
1520 flayer = fore->w_savelayer;
1521 DoCommand(args, argl);
1522 rc_name = oldrcname;
1524 #ifdef MULTIUSER
1525 EffectiveAclUser = 0;
1526 #endif
1529 #ifndef NAMEDPIPE
1532 SendAttachMsg(s, m, fd)
1533 int s;
1534 struct msg *m;
1535 int fd;
1537 int r;
1538 struct msghdr msg;
1539 struct iovec iov;
1540 char buf[CMSG_SPACE(sizeof(int))];
1541 struct cmsghdr *cmsg;
1543 iov.iov_base = (char *)m;
1544 iov.iov_len = sizeof(*m);
1545 bzero(&msg, sizeof(msg));
1546 msg.msg_name = 0;
1547 msg.msg_namelen = 0;
1548 msg.msg_iov = &iov;
1549 msg.msg_iovlen = 1;
1550 msg.msg_control = buf;
1551 msg.msg_controllen = sizeof(buf);
1552 cmsg = CMSG_FIRSTHDR(&msg);
1553 cmsg->cmsg_level = SOL_SOCKET;
1554 cmsg->cmsg_type = SCM_RIGHTS;
1555 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
1556 bcopy(&fd, CMSG_DATA(cmsg), sizeof(int));
1557 msg.msg_controllen = cmsg->cmsg_len;
1558 while(1)
1560 r = sendmsg(s, &msg, 0);
1561 if (r == -1 && errno == EINTR)
1562 continue;
1563 if (r == -1)
1564 return -1;
1565 return 0;
1569 #endif