Copyright for 2009
[screen-lua.git] / src / socket.c
blobacdd7d1aa70d948445390a861ff7e3950f12a24f
1 /* Copyright (c) 2008, 2009
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Micah Cowan (micah@cowan.name)
5 * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
6 * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
7 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
8 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
9 * Copyright (c) 1987 Oliver Laumann
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3, or (at your option)
14 * any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program (see the file COPYING); if not, see
23 * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
26 ****************************************************************
29 #include "config.h"
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #if !defined(NAMEDPIPE)
34 #include <sys/socket.h>
35 #include <sys/un.h>
36 #endif
38 #ifndef SIGINT
39 # include <signal.h>
40 #endif
42 #include "screen.h"
44 #ifdef HAVE_DIRENT_H
45 # include <dirent.h>
46 #else
47 # include <sys/dir.h>
48 # define dirent direct
49 #endif
51 #include "extern.h"
53 static int CheckPid __P((int));
54 static void ExecCreate __P((struct msg *));
55 static void DoCommandMsg __P((struct msg *));
56 #if defined(_SEQUENT_) && !defined(NAMEDPIPE)
57 # define connect sconnect /* _SEQUENT_ has braindamaged connect */
58 static int sconnect __P((int, struct sockaddr *, int));
59 #endif
60 static void FinishAttach __P((struct msg *));
61 static void FinishDetach __P((struct msg *));
62 static void AskPassword __P((struct msg *));
65 extern char *RcFileName, *extra_incap, *extra_outcap;
66 extern int ServerSocket, real_uid, real_gid, eff_uid, eff_gid;
67 extern int dflag, iflag, rflag, lsflag, quietflag, wipeflag, xflag;
68 extern char *attach_tty, *LoginName, HostName[];
69 extern struct display *display, *displays;
70 extern struct win *fore, *wtab[], *console_window, *windows;
71 extern struct layer *flayer;
72 extern struct layout *layout_attach, *layout_last, layout_last_marker;
73 extern struct NewWindow nwin_undef;
74 #ifdef MULTIUSER
75 extern char *multi;
76 #endif
78 extern char *getenv();
80 extern char SockPath[];
81 extern struct event serv_read;
82 extern char *rc_name;
83 extern struct comm comms[];
85 #ifdef MULTIUSER
86 # define SOCKMODE (S_IWRITE | S_IREAD | (displays ? S_IEXEC : 0) | (multi ? 1 : 0))
87 #else
88 # define SOCKMODE (S_IWRITE | S_IREAD | (displays ? S_IEXEC : 0))
89 #endif
93 * Socket directory manager
95 * fdp: pointer to store the first good socket.
96 * nfoundp: pointer to store the number of sockets found matching.
97 * notherp: pointer to store the number of sockets not matching.
98 * match: string to match socket name.
100 * The socket directory must be in SockPath!
101 * The global variables LoginName, multi, rflag, xflag, dflag,
102 * quietflag, SockPath are used.
104 * The first good socket is stored in fdp and its name is
105 * appended to SockPath.
106 * If none exists or fdp is NULL SockPath is not changed.
108 * Returns: number of good sockets.
113 FindSocket(fdp, nfoundp, notherp, match)
114 int *fdp;
115 int *nfoundp, *notherp;
116 char *match;
118 DIR *dirp;
119 struct dirent *dp;
120 struct stat st;
121 int mode;
122 int sdirlen;
123 int matchlen = 0;
124 char *name, *n;
125 int firsts = -1, sockfd;
126 char *firstn = NULL;
127 int nfound = 0, ngood = 0, ndead = 0, nwipe = 0, npriv = 0;
128 int nperfect = 0;
129 struct sent
131 struct sent *next;
132 int mode;
133 char *name;
134 } *slist, **slisttail, *sent, *nsent;
136 if (match)
138 matchlen = strlen(match);
139 #ifdef NAME_MAX
140 if (matchlen > NAME_MAX)
141 matchlen = NAME_MAX;
142 #endif
146 * SockPath contains the socket directory.
147 * At the end of FindSocket the socket name will be appended to it.
148 * Thus FindSocket() can only be called once!
150 sdirlen = strlen(SockPath);
152 #ifdef USE_SETEUID
153 xseteuid(real_uid);
154 xsetegid(real_gid);
155 #endif
157 if ((dirp = opendir(SockPath)) == 0)
158 Panic(errno, "Cannot opendir %s", SockPath);
160 slist = 0;
161 slisttail = &slist;
162 while ((dp = readdir(dirp)))
164 int cmatch = 0;
165 name = dp->d_name;
166 debug1("- %s\n", name);
167 if (*name == 0 || *name == '.' || strlen(name) > 2*MAXSTR)
168 continue;
169 if (matchlen)
171 n = name;
172 /* if we don't want to match digits. Skip them */
173 if ((*match <= '0' || *match > '9') && (*n > '0' && *n <= '9'))
175 while (*n >= '0' && *n <= '9')
176 n++;
177 if (*n == '.')
178 n++;
180 /* the tty prefix is optional */
181 if (strncmp(match, "tty", 3) && strncmp(n, "tty", 3) == 0)
182 n += 3;
183 if (strncmp(match, n, matchlen))
184 continue;
185 cmatch = (*(n + matchlen) == 0);
186 debug1(" -> matched %s\n", match);
188 sprintf(SockPath + sdirlen, "/%s", name);
190 debug1("stat %s\n", SockPath);
191 errno = 0;
192 debug2("uid = %d, gid = %d\n", getuid(), getgid());
193 debug2("euid = %d, egid = %d\n", geteuid(), getegid());
194 if (stat(SockPath, &st))
196 debug1("errno = %d\n", errno);
197 continue;
200 #ifndef SOCK_NOT_IN_FS
201 # ifdef NAMEDPIPE
202 # ifdef S_ISFIFO
203 debug("S_ISFIFO?\n");
204 if (!S_ISFIFO(st.st_mode))
205 continue;
206 # endif
207 # else
208 # ifdef S_ISSOCK
209 debug("S_ISSOCK?\n");
210 if (!S_ISSOCK(st.st_mode))
211 continue;
212 # endif
213 # endif
214 #endif
216 debug2("st.st_uid = %d, real_uid = %d\n", st.st_uid, real_uid);
217 if ((int)st.st_uid != real_uid)
218 continue;
219 mode = (int)st.st_mode & 0777;
220 debug1(" has mode 0%03o\n", mode);
221 #ifdef MULTIUSER
222 if (multi && ((mode & 0677) != 0601))
224 debug(" is not a MULTI-USER session");
225 if (strcmp(multi, LoginName))
227 debug(" and we are in a foreign directory.\n");
228 mode = -4;
230 else
232 debug(", but it is our own session.\n");
235 #endif
236 debug(" store it.\n");
237 if ((sent = (struct sent *)malloc(sizeof(struct sent))) == 0)
238 continue;
239 sent->next = 0;
240 sent->name = SaveStr(name);
241 sent->mode = mode;
242 *slisttail = sent;
243 slisttail = &sent->next;
244 nfound++;
245 sockfd = MakeClientSocket(0);
246 #ifdef USE_SETEUID
247 /* MakeClientSocket sets ids back to eff */
248 xseteuid(real_uid);
249 xsetegid(real_gid);
250 #endif
251 if (sockfd == -1)
253 debug2(" MakeClientSocket failed, unreachable? %d %d\n",
254 matchlen, wipeflag);
255 sent->mode = -3;
256 #ifndef SOCKDIR_IS_LOCAL_TO_HOST
257 /* Unreachable - it is dead if we detect that it's local
258 * or we specified a match
260 n = name + strlen(name) - 1;
261 while (n != name && *n != '.')
262 n--;
263 if (matchlen == 0 && !(*n == '.' && n[1] && strncmp(HostName, n + 1, strlen(n + 1)) == 0))
265 npriv++; /* a good socket that was not for us */
266 continue;
268 #endif
269 ndead++;
270 sent->mode = -1;
271 if (wipeflag)
273 if (unlink(SockPath) == 0)
275 sent->mode = -2;
276 nwipe++;
279 continue;
282 mode &= 0776;
283 /* Shall we connect ? */
284 debug2(" connecting: mode=%03o, rflag=%d, ", mode, rflag);
285 debug2("xflag=%d, dflag=%d ?\n", xflag, dflag);
288 * mode 600: socket is detached.
289 * mode 700: socket is attached.
290 * xflag implies rflag here.
292 * fail, when socket mode mode is not 600 or 700
293 * fail, when we want to detach w/o reattach, but it already is detached.
294 * fail, when we only want to attach, but mode 700 and not xflag.
295 * fail, if none of dflag, rflag, xflag is set.
297 if ((mode != 0700 && mode != 0600) ||
298 (dflag && !rflag && !xflag && mode == 0600) ||
299 (!dflag && rflag && mode == 0700 && !xflag) ||
300 (!dflag && !rflag && !xflag))
302 close(sockfd);
303 debug(" no!\n");
304 npriv++; /* a good socket that was not for us */
305 continue;
307 ngood++;
308 if (cmatch)
309 nperfect++;
310 if (fdp && (firsts == -1 || (cmatch && nperfect == 1)))
312 if (firsts != -1)
313 close(firsts);
314 firsts = sockfd;
315 firstn = sent->name;
316 debug(" taken.\n");
318 else
320 debug(" discarded.\n");
321 close(sockfd);
324 (void)closedir(dirp);
325 if (!lsflag && nperfect == 1)
326 ngood = nperfect;
327 if (nfound && (lsflag || ngood != 1) && !quietflag)
329 switch(ngood)
331 case 0:
332 Msg(0, nfound > 1 ? "There are screens on:" : "There is a screen on:");
333 break;
334 case 1:
335 Msg(0, nfound > 1 ? "There are several screens on:" : "There is a suitable screen on:");
336 break;
337 default:
338 Msg(0, "There are several suitable screens on:");
339 break;
341 for (sent = slist; sent; sent = sent->next)
343 switch (sent->mode)
345 case 0700:
346 printf("\t%s\t(Attached)\n", sent->name);
347 break;
348 case 0600:
349 printf("\t%s\t(Detached)\n", sent->name);
350 break;
351 #ifdef MULTIUSER
352 case 0701:
353 printf("\t%s\t(Multi, attached)\n", sent->name);
354 break;
355 case 0601:
356 printf("\t%s\t(Multi, detached)\n", sent->name);
357 break;
358 #endif
359 case -1:
360 /* No trigraphs here! */
361 printf("\t%s\t(Dead ?%c?)\n", sent->name, '?');
362 break;
363 case -2:
364 printf("\t%s\t(Removed)\n", sent->name);
365 break;
366 case -3:
367 printf("\t%s\t(Remote or dead)\n", sent->name);
368 break;
369 case -4:
370 printf("\t%s\t(Private)\n", sent->name);
371 break;
375 if (ndead && !quietflag)
377 char *m = "Remove dead screens with 'screen -wipe'.";
378 if (wipeflag)
379 Msg(0, "%d socket%s wiped out.", nwipe, nwipe > 1 ? "s" : "");
380 else
381 Msg(0, m, ndead > 1 ? "s" : "", ndead > 1 ? "" : "es"); /* other args for nethack */
383 if (firsts != -1)
385 sprintf(SockPath + sdirlen, "/%s", firstn);
386 *fdp = firsts;
388 else
389 SockPath[sdirlen] = 0;
390 for (sent = slist; sent; sent = nsent)
392 nsent = sent->next;
393 free(sent->name);
394 free((char *)sent);
396 #ifdef USE_SETEUID
397 xseteuid(eff_uid);
398 xsetegid(eff_gid);
399 #endif
400 if (notherp)
401 *notherp = npriv;
402 if (nfoundp)
403 *nfoundp = nfound - nwipe;
404 return ngood;
410 ** Socket/pipe create routines
414 #ifdef NAMEDPIPE
417 MakeServerSocket()
419 register int s;
420 struct stat st;
422 # ifdef USE_SETEUID
423 xseteuid(real_uid);
424 xsetegid(real_gid);
425 # endif
426 if ((s = open(SockPath, O_WRONLY | O_NONBLOCK)) >= 0)
428 debug("huii, my fifo already exists??\n");
429 if (quietflag)
431 Kill(D_userpid, SIG_BYE);
432 eexit(11);
434 Msg(0, "There is already a screen running on %s.", Filename(SockPath));
435 if (stat(SockPath, &st) == -1)
436 Panic(errno, "stat");
437 if ((int)st.st_uid != real_uid)
438 Panic(0, "Unfortunatelly you are not its owner.");
439 if ((st.st_mode & 0700) == 0600)
440 Panic(0, "To resume it, use \"screen -r\"");
441 else
442 Panic(0, "It is not detached.");
443 /* NOTREACHED */
445 # ifdef USE_SETEUID
446 (void) unlink(SockPath);
447 if (mkfifo(SockPath, SOCKMODE))
448 Panic(0, "mkfifo %s failed", SockPath);
449 # ifdef BROKEN_PIPE
450 if ((s = open(SockPath, O_RDWR | O_NONBLOCK, 0)) < 0)
451 # else
452 if ((s = open(SockPath, O_RDONLY | O_NONBLOCK, 0)) < 0)
453 # endif
454 Panic(errno, "open fifo %s", SockPath);
455 xseteuid(eff_uid);
456 xsetegid(eff_gid);
457 return s;
458 # else /* !USE_SETEUID */
459 if (UserContext() > 0)
461 (void) unlink(SockPath);
462 UserReturn(mkfifo(SockPath, SOCKMODE));
464 if (UserStatus())
465 Panic(0, "mkfifo %s failed", SockPath);
466 # ifdef BROKEN_PIPE
467 if ((s = secopen(SockPath, O_RDWR | O_NONBLOCK, 0)) < 0)
468 # else
469 if ((s = secopen(SockPath, O_RDONLY | O_NONBLOCK, 0)) < 0)
470 # endif
471 Panic(errno, "open fifo %s", SockPath);
472 return s;
473 # endif /* !USE_SETEUID */
478 MakeClientSocket(err)
479 int err;
481 register int s = 0;
483 if ((s = secopen(SockPath, O_WRONLY | O_NONBLOCK, 0)) >= 0)
485 (void) fcntl(s, F_SETFL, 0);
486 return s;
488 if (err)
489 Msg(errno, "%s", SockPath);
490 debug2("MakeClientSocket() open %s failed (%d)\n", SockPath, errno);
491 return -1;
495 #else /* NAMEDPIPE */
499 MakeServerSocket()
501 register int s;
502 struct sockaddr_un a;
503 struct stat st;
505 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
506 Panic(errno, "socket");
507 a.sun_family = AF_UNIX;
508 strncpy(a.sun_path, SockPath, sizeof(a.sun_path));
509 a.sun_path[sizeof(a.sun_path) - 1] = 0;
510 # ifdef USE_SETEUID
511 xseteuid(real_uid);
512 xsetegid(real_gid);
513 # endif
514 if (connect(s, (struct sockaddr *) &a, strlen(SockPath) + 2) != -1)
516 debug("oooooh! socket already is alive!\n");
517 if (quietflag)
519 Kill(D_userpid, SIG_BYE);
521 * oh, well. nobody receives that return code. papa
522 * dies by signal.
524 eexit(11);
526 Msg(0, "There is already a screen running on %s.", Filename(SockPath));
527 if (stat(SockPath, &st) == -1)
528 Panic(errno, "stat");
529 if (st.st_uid != real_uid)
530 Panic(0, "Unfortunatelly you are not its owner.");
531 if ((st.st_mode & 0700) == 0600)
532 Panic(0, "To resume it, use \"screen -r\"");
533 else
534 Panic(0, "It is not detached.");
535 /* NOTREACHED */
537 #if defined(m88k) || defined(sysV68)
538 close(s); /* we get bind: Invalid argument if this is not done */
539 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
540 Panic(errno, "reopen socket");
541 #endif
542 (void) unlink(SockPath);
543 if (bind(s, (struct sockaddr *) & a, strlen(SockPath) + 2) == -1)
544 Panic(errno, "bind (%s)", SockPath);
545 #ifdef SOCK_NOT_IN_FS
547 int f;
548 if ((f = secopen(SockPath, O_RDWR | O_CREAT, SOCKMODE)) < 0)
549 Panic(errno, "shadow socket open");
550 close(f);
552 #else
553 chmod(SockPath, SOCKMODE);
554 # ifndef USE_SETEUID
555 chown(SockPath, real_uid, real_gid);
556 # endif
557 #endif /* SOCK_NOT_IN_FS */
558 if (listen(s, 5) == -1)
559 Panic(errno, "listen");
560 # ifdef F_SETOWN
561 fcntl(s, F_SETOWN, getpid());
562 debug1("Serversocket owned by %d\n", fcntl(s, F_GETOWN, 0));
563 # endif /* F_SETOWN */
564 # ifdef USE_SETEUID
565 xseteuid(eff_uid);
566 xsetegid(eff_gid);
567 # endif
568 return s;
572 MakeClientSocket(err)
573 int err;
575 register int s;
576 struct sockaddr_un a;
578 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
579 Panic(errno, "socket");
580 a.sun_family = AF_UNIX;
581 strncpy(a.sun_path, SockPath, sizeof(a.sun_path));
582 a.sun_path[sizeof(a.sun_path) - 1] = 0;
583 # ifdef USE_SETEUID
584 xseteuid(real_uid);
585 xsetegid(real_gid);
586 # else
587 if (access(SockPath, W_OK))
589 if (err)
590 Msg(errno, "%s", SockPath);
591 debug2("MakeClientSocket: access(%s): %d.\n", SockPath, errno);
592 close(s);
593 return -1;
595 # endif
596 if (connect(s, (struct sockaddr *) &a, strlen(SockPath) + 2) == -1)
598 if (err)
599 Msg(errno, "%s: connect", SockPath);
600 debug("MakeClientSocket: connect failed.\n");
601 close(s);
602 s = -1;
604 # ifdef USE_SETEUID
605 xseteuid(eff_uid);
606 xsetegid(eff_gid);
607 # endif
608 return s;
610 #endif /* NAMEDPIPE */
615 ** Message send and receive routines
619 void
620 SendCreateMsg(sty, nwin)
621 char *sty;
622 struct NewWindow *nwin;
624 int s;
625 struct msg m;
626 register char *p;
627 register int len, n;
628 char **av = nwin->args;
630 #ifdef NAME_MAX
631 if (strlen(sty) > NAME_MAX)
632 sty[NAME_MAX] = 0;
633 #endif
634 if (strlen(sty) > 2 * MAXSTR - 1)
635 sty[2 * MAXSTR - 1] = 0;
636 sprintf(SockPath + strlen(SockPath), "/%s", sty);
637 if ((s = MakeClientSocket(1)) == -1)
638 exit(1);
639 debug1("SendCreateMsg() to '%s'\n", SockPath);
640 bzero((char *)&m, sizeof(m));
641 m.type = MSG_CREATE;
642 strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1);
643 m.m_tty[sizeof(m.m_tty) - 1] = 0;
644 p = m.m.create.line;
645 n = 0;
646 if (nwin->args != nwin_undef.args)
647 for (av = nwin->args; *av && n < MAXARGS - 1; ++av, ++n)
649 len = strlen(*av) + 1;
650 if (p + len >= m.m.create.line + sizeof(m.m.create.line) - 1)
651 break;
652 strcpy(p, *av);
653 p += len;
655 if (nwin->aka != nwin_undef.aka && p + strlen(nwin->aka) + 1 < m.m.create.line + sizeof(m.m.create.line))
656 strcpy(p, nwin->aka);
657 else
658 *p = '\0';
659 m.m.create.nargs = n;
660 m.m.create.aflag = nwin->aflag;
661 m.m.create.flowflag = nwin->flowflag;
662 m.m.create.lflag = nwin->lflag;
663 m.m.create.hheight = nwin->histheight;
664 if (getcwd(m.m.create.dir, sizeof(m.m.create.dir)) == 0)
666 Msg(errno, "getcwd");
667 return;
669 if (nwin->term != nwin_undef.term)
670 strncpy(m.m.create.screenterm, nwin->term, 19);
671 m.m.create.screenterm[19] = '\0';
672 m.protocol_revision = MSG_REVISION;
673 debug1("SendCreateMsg writing '%s'\n", m.m.create.line);
674 if (write(s, (char *) &m, sizeof m) != sizeof m)
675 Msg(errno, "write");
676 close(s);
680 SendErrorMsg(tty, buf)
681 char *tty, *buf;
683 int s;
684 struct msg m;
686 strncpy(m.m.message, buf, sizeof(m.m.message) - 1);
687 m.m.message[sizeof(m.m.message) - 1] = 0;
688 s = MakeClientSocket(0);
689 if (s < 0)
690 return -1;
691 m.type = MSG_ERROR;
692 strncpy(m.m_tty, tty, sizeof(m.m_tty) - 1);
693 m.m_tty[sizeof(m.m_tty) - 1] = 0;
694 m.protocol_revision = MSG_REVISION;
695 debug1("SendErrorMsg(): writing to '%s'\n", SockPath);
696 (void) write(s, (char *) &m, sizeof m);
697 close(s);
698 return 0;
701 static void
702 ExecCreate(mp)
703 struct msg *mp;
705 struct NewWindow nwin;
706 char *args[MAXARGS];
707 register int n;
708 register char **pp = args, *p = mp->m.create.line;
710 nwin = nwin_undef;
711 n = mp->m.create.nargs;
712 if (n > MAXARGS - 1)
713 n = MAXARGS - 1;
714 /* ugly hack alert... should be done by the frontend! */
715 if (n)
717 int l, num;
718 char buf[20];
720 l = strlen(p);
721 if (IsNumColon(p, 10, buf, sizeof(buf)))
723 if (*buf)
724 nwin.aka = buf;
725 num = atoi(p);
726 if (num < 0 || num > MAXWIN - 1)
727 num = 0;
728 nwin.StartAt = num;
729 p += l + 1;
730 n--;
733 for (; n > 0; n--)
735 *pp++ = p;
736 p += strlen(p) + 1;
738 *pp = 0;
739 if (*p)
740 nwin.aka = p;
741 if (*args)
742 nwin.args = args;
743 nwin.aflag = mp->m.create.aflag;
744 nwin.flowflag = mp->m.create.flowflag;
745 if (*mp->m.create.dir)
746 nwin.dir = mp->m.create.dir;
747 nwin.lflag = mp->m.create.lflag;
748 nwin.histheight = mp->m.create.hheight;
749 if (*mp->m.create.screenterm)
750 nwin.term = mp->m.create.screenterm;
751 MakeWindow(&nwin);
754 static int
755 CheckPid(pid)
756 int pid;
758 debug1("Checking pid %d\n", pid);
759 if (pid < 2)
760 return -1;
761 if (eff_uid == real_uid)
762 return kill(pid, 0);
763 if (UserContext() > 0)
764 UserReturn(kill(pid, 0));
765 return UserStatus();
768 #ifdef hpux
770 * From: "F. K. Bruner" <napalm@ugcs.caltech.edu>
771 * From: "Dan Egnor" <egnor@oracorp.com> Tue Aug 10 06:56:45 1993
772 * The problem is that under HPUX (and possibly other systems too) there are
773 * two equivalent device files for each pty/tty device:
774 * /dev/ttyxx == /dev/pty/ttyxx
775 * /dev/ptyxx == /dev/ptym/ptyxx
776 * I didn't look into the exact specifics, but I've run across this problem
777 * before: Even if you open /dev/ttyxx as fds 0 1 & 2 for a process, if that
778 * process calls the system to determine its tty, it'll get /dev/pty/ttyxx.
780 * Earlier versions seemed to work -- wonder what they did.
782 static int
783 ttycmp(s1, s2)
784 char *s1, *s2;
786 if (strlen(s1) > 5) s1 += strlen(s1) - 5;
787 if (strlen(s2) > 5) s2 += strlen(s2) - 5;
788 return strcmp(s1, s2);
790 # define TTYCMP(a, b) ttycmp(a, b)
791 #else
792 # define TTYCMP(a, b) strcmp(a, b)
793 #endif
795 static int
796 CreateTempDisplay(m, recvfd, wi)
797 struct msg *m;
798 int recvfd;
799 struct win *wi;
801 int pid;
802 int attach;
803 char *user;
804 int i;
805 struct mode Mode;
806 struct display *olddisplays = displays;
808 switch (m->type)
810 case MSG_CONT:
811 case MSG_ATTACH:
812 pid = m->m.attach.apid;
813 user = m->m.attach.auser;
814 attach = 1;
815 break;
816 #ifdef REMOTE_DETACH
817 case MSG_DETACH:
818 # ifdef POW_DETACH
819 case MSG_POW_DETACH:
820 # endif /* POW_DETACH */
821 pid = m->m.detach.dpid;
822 user = m->m.detach.duser;
823 attach = 0;
824 break;
825 #endif
826 default:
827 return -1;
830 if (CheckPid(pid))
832 Msg(0, "Attach attempt with bad pid(%d)!", pid);
833 return -1;
835 if (recvfd != -1)
837 char *myttyname;
838 i = recvfd;
839 recvfd = -1;
840 myttyname = ttyname(i);
841 if (myttyname == 0 || strcmp(myttyname, m->m_tty))
843 Msg(errno, "Attach: passed fd does not match tty: %s - %s!", m->m_tty, myttyname ? myttyname : "NULL");
844 close(i);
845 Kill(pid, SIG_BYE);
846 return -1;
849 else if ((i = secopen(m->m_tty, O_RDWR | O_NONBLOCK, 0)) < 0)
851 Msg(errno, "Attach: Could not open %s!", m->m_tty);
852 Kill(pid, SIG_BYE);
853 return -1;
855 #ifdef MULTIUSER
856 if (attach)
857 Kill(pid, SIGCONT);
858 #endif
860 #if defined(ultrix) || defined(pyr) || defined(NeXT)
861 brktty(i); /* for some strange reason this must be done */
862 #endif
864 if (attach)
866 if (display || wi)
868 write(i, "Attaching from inside of screen?\n", 33);
869 close(i);
870 Kill(pid, SIG_BYE);
871 Msg(0, "Attach msg ignored: coming from inside.");
872 return -1;
875 #ifdef MULTIUSER
876 if (strcmp(user, LoginName))
877 if (*FindUserPtr(user) == 0)
879 write(i, "Access to session denied.\n", 26);
880 close(i);
881 Kill(pid, SIG_BYE);
882 Msg(0, "Attach: access denied for user %s.", user);
883 return -1;
885 #endif
887 debug2("RecMsg: apid %d is o.k. and we just opened '%s'\n", pid, m->m_tty);
888 #ifndef MULTI
889 if (displays)
891 write(i, "Screen session in use.\n", 23);
892 close(i);
893 Kill(pid, SIG_BYE);
894 return -1;
896 #endif
899 /* create new display */
900 GetTTY(i, &Mode);
901 if (MakeDisplay(user, m->m_tty, attach ? m->m.attach.envterm : "", i, pid, &Mode) == 0)
903 write(i, "Could not make display.\n", 24);
904 close(i);
905 Msg(0, "Attach: could not make display for user %s", user);
906 Kill(pid, SIG_BYE);
907 return -1;
909 #ifdef ENCODINGS
910 if (attach)
912 # ifdef UTF8
913 D_encoding = m->m.attach.encoding == 1 ? UTF8 : m->m.attach.encoding ? m->m.attach.encoding - 1 : 0;
914 # else
915 D_encoding = m->m.attach.encoding ? m->m.attach.encoding - 1 : 0;
916 # endif
917 if (D_encoding < 0 || !EncodingName(D_encoding))
918 D_encoding = 0;
920 #endif
922 if (iflag && olddisplays)
924 iflag = 0;
925 #if defined(TERMIO) || defined(POSIX)
926 olddisplays->d_NewMode.tio.c_cc[VINTR] = VDISABLE;
927 olddisplays->d_NewMode.tio.c_lflag &= ~ISIG;
928 #else /* TERMIO || POSIX */
929 olddisplays->d_NewMode.m_tchars.t_intrc = -1;
930 #endif /* TERMIO || POSIX */
931 SetTTY(olddisplays->d_userfd, &olddisplays->d_NewMode);
933 SetMode(&D_OldMode, &D_NewMode, D_flow, iflag);
934 SetTTY(D_userfd, &D_NewMode);
935 if (fcntl(D_userfd, F_SETFL, FNBLOCK))
936 Msg(errno, "Warning: NBLOCK fcntl failed");
937 return 0;
940 void
941 ReceiveMsg()
943 int left, len;
944 static struct msg m;
945 char *p;
946 int ns = ServerSocket;
947 struct win *wi;
948 int recvfd = -1;
949 struct acluser *user;
951 #ifdef NAMEDPIPE
952 debug("Ha, there was someone knocking on my fifo??\n");
953 if (fcntl(ServerSocket, F_SETFL, 0) == -1)
954 Panic(errno, "BLOCK fcntl");
955 p = (char *) &m;
956 left = sizeof(m);
957 #else
958 struct sockaddr_un a;
959 struct msghdr msg;
960 struct iovec iov;
961 char control[1024];
963 len = sizeof(a);
964 debug("Ha, there was someone knocking on my socket??\n");
965 if ((ns = accept(ns, (struct sockaddr *) &a, (void *)&len)) < 0)
967 Msg(errno, "accept");
968 return;
971 p = (char *) &m;
972 left = sizeof(m);
973 bzero(&msg, sizeof(msg));
974 iov.iov_base = &m;
975 iov.iov_len = left;
976 msg.msg_iov = &iov;
977 msg.msg_iovlen = 1;
978 msg.msg_controllen = sizeof(control);
979 msg.msg_control = &control;
980 while (left > 0)
982 len = recvmsg(ns, &msg, 0);
983 if (len < 0 && errno == EINTR)
984 continue;
985 if (len < 0)
987 close(ns);
988 Msg(errno, "read");
989 return;
991 if (msg.msg_controllen)
993 struct cmsghdr *cmsg;
994 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
996 int cl;
997 char *cp;
998 if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS)
999 continue;
1000 cp = (char *)CMSG_DATA(cmsg);
1001 cl = cmsg->cmsg_len;
1002 while(cl >= CMSG_LEN(sizeof(int)))
1004 int passedfd;
1005 bcopy(cp, &passedfd, sizeof(int));
1006 if (recvfd >= 0 && passedfd != recvfd)
1007 close(recvfd);
1008 recvfd = passedfd;
1009 cl -= CMSG_LEN(sizeof(int));
1013 p += len;
1014 left -= len;
1015 break;
1018 #endif
1020 while (left > 0)
1022 len = read(ns, p, left);
1023 if (len < 0 && errno == EINTR)
1024 continue;
1025 if (len <= 0)
1026 break;
1027 p += len;
1028 left -= len;
1031 #ifdef NAMEDPIPE
1032 # ifndef BROKEN_PIPE
1033 /* Reopen pipe to prevent EOFs at the select() call */
1034 close(ServerSocket);
1035 if ((ServerSocket = secopen(SockPath, O_RDONLY | O_NONBLOCK, 0)) < 0)
1036 Panic(errno, "reopen fifo %s", SockPath);
1037 evdeq(&serv_read);
1038 serv_read.fd = ServerSocket;
1039 evenq(&serv_read);
1040 # endif
1041 #else
1042 close(ns);
1043 #endif
1045 if (len < 0)
1047 Msg(errno, "read");
1048 if (recvfd != -1)
1049 close(recvfd);
1050 return;
1052 if (left > 0)
1054 if (left != sizeof(m))
1055 Msg(0, "Message %d of %d bytes too small", left, (int)sizeof(m));
1056 else
1057 debug("No data on socket.\n");
1058 return;
1060 if (m.protocol_revision != MSG_REVISION)
1062 if (recvfd != -1)
1063 close(recvfd);
1064 Msg(0, "Invalid message (magic 0x%08x).", m.protocol_revision);
1065 return;
1068 debug2("*** RecMsg: type %d tty %s\n", m.type, m.m_tty);
1069 if (m.type != MSG_ATTACH && recvfd != -1)
1071 close(recvfd);
1072 recvfd = -1;
1075 for (display = displays; display; display = display->d_next)
1076 if (TTYCMP(D_usertty, m.m_tty) == 0)
1077 break;
1078 debug2("display: %s display %sfound\n", m.m_tty, display ? "" : "not ");
1079 wi = 0;
1080 if (!display)
1082 for (wi = windows; wi; wi = wi->w_next)
1083 if (!TTYCMP(m.m_tty, wi->w_tty))
1085 /* XXX: hmmm, rework this? */
1086 display = wi->w_layer.l_cvlist ? wi->w_layer.l_cvlist->c_display : 0;
1087 debug2("but window %s %sfound.\n", m.m_tty, display ? "" :
1088 "(backfacing)");
1089 break;
1093 /* Remove the status to prevent garbage on the screen */
1094 if (display && D_status)
1095 RemoveStatus();
1097 if (display && !D_tcinited && m.type != MSG_HANGUP)
1099 if (recvfd != -1)
1100 close(recvfd);
1101 return; /* ignore messages for bad displays */
1104 switch (m.type)
1106 case MSG_WINCH:
1107 if (display)
1108 CheckScreenSize(1); /* Change fore */
1109 break;
1110 case MSG_CREATE:
1112 * the window that issued the create message need not be an active
1113 * window. Then we create the window without having a display.
1114 * Resulting in another inactive window.
1116 ExecCreate(&m);
1117 break;
1118 case MSG_CONT:
1119 if (display && D_userpid != 0 && kill(D_userpid, 0) == 0)
1120 break; /* Intruder Alert */
1121 debug2("RecMsg: apid=%d,was %d\n", m.m.attach.apid, display ? D_userpid : 0);
1122 /* FALLTHROUGH */
1124 case MSG_ATTACH:
1125 if (CreateTempDisplay(&m, recvfd, wi))
1126 break;
1127 #ifdef PASSWORD
1128 if (D_user->u_password && *D_user->u_password)
1129 AskPassword(&m);
1130 else
1131 #endif
1132 FinishAttach(&m);
1133 break;
1134 case MSG_ERROR:
1135 Msg(0, "%s", m.m.message);
1136 break;
1137 case MSG_HANGUP:
1138 if (!wi) /* ignore hangups from inside */
1139 Hangup();
1140 break;
1141 #ifdef REMOTE_DETACH
1142 case MSG_DETACH:
1143 # ifdef POW_DETACH
1144 case MSG_POW_DETACH:
1145 # endif /* POW_DETACH */
1146 #ifdef PASSWORD
1147 user = *FindUserPtr(m.m.detach.duser);
1148 if (user && user->u_password && *user->u_password)
1150 if (CreateTempDisplay(&m, recvfd, 0))
1151 break;
1152 AskPassword(&m);
1154 else
1155 #endif /* PASSWORD */
1156 FinishDetach(&m);
1157 break;
1158 #endif
1159 case MSG_COMMAND:
1160 DoCommandMsg(&m);
1161 break;
1162 default:
1163 Msg(0, "Invalid message (type %d).", m.type);
1167 #if defined(_SEQUENT_) && !defined(NAMEDPIPE)
1168 #undef connect
1170 * sequent_ptx socket emulation must have mode 000 on the socket!
1172 static int
1173 sconnect(s, sapp, len)
1174 int s, len;
1175 struct sockaddr *sapp;
1177 register struct sockaddr_un *sap;
1178 struct stat st;
1179 int x;
1181 sap = (struct sockaddr_un *)sapp;
1182 if (stat(sap->sun_path, &st))
1183 return -1;
1184 chmod(sap->sun_path, 0);
1185 x = connect(s, (struct sockaddr *) sap, len);
1186 chmod(sap->sun_path, st.st_mode);
1187 return x;
1189 #endif
1193 * Set the mode bits of the socket to the current status
1196 chsock()
1198 int r, euid = geteuid();
1199 if (euid != real_uid)
1201 if (UserContext() <= 0)
1202 return UserStatus();
1204 r = chmod(SockPath, SOCKMODE);
1206 * Sockets usually reside in the /tmp/ area, where sysadmin scripts
1207 * may be happy to remove old files. We manually prevent the socket
1208 * from becoming old. (chmod does not touch mtime).
1210 (void)utimes(SockPath, NULL);
1212 if (euid != real_uid)
1213 UserReturn(r);
1214 return r;
1218 * Try to recreate the socket/pipe
1221 RecoverSocket()
1223 close(ServerSocket);
1224 if ((int)geteuid() != real_uid)
1226 if (UserContext() > 0)
1227 UserReturn(unlink(SockPath));
1228 (void)UserStatus();
1230 else
1231 (void) unlink(SockPath);
1233 if ((ServerSocket = MakeServerSocket()) < 0)
1234 return 0;
1235 evdeq(&serv_read);
1236 serv_read.fd = ServerSocket;
1237 evenq(&serv_read);
1238 return 1;
1242 static void
1243 FinishAttach(m)
1244 struct msg *m;
1246 char *p;
1247 int pid;
1248 int noshowwin;
1249 struct win *wi;
1251 ASSERT(display);
1252 pid = D_userpid;
1254 #ifdef REMOTE_DETACH
1255 if (m->m.attach.detachfirst == MSG_DETACH
1256 # ifdef POW_DETACH
1257 || m->m.attach.detachfirst == MSG_POW_DETACH
1258 # endif
1260 FinishDetach(m);
1261 #endif
1263 #if defined(pyr) || defined(xelos) || defined(sequent)
1265 * Kludge for systems with braindamaged termcap routines,
1266 * which evaluate $TERMCAP, regardless weather it describes
1267 * the correct terminal type or not.
1269 debug("unsetenv(TERMCAP) in case of a different terminal");
1270 unsetenv("TERMCAP");
1271 #endif
1274 * We reboot our Terminal Emulator. Forget all we knew about
1275 * the old terminal, reread the termcap entries in .screenrc
1276 * (and nothing more from .screenrc is read. Mainly because
1277 * I did not check, weather a full reinit is safe. jw)
1278 * and /etc/screenrc, and initialise anew.
1280 if (extra_outcap)
1281 free(extra_outcap);
1282 if (extra_incap)
1283 free(extra_incap);
1284 extra_incap = extra_outcap = 0;
1285 debug2("Message says size (%dx%d)\n", m->m.attach.columns, m->m.attach.lines);
1286 #ifdef ETCSCREENRC
1287 # ifdef ALLOW_SYSSCREENRC
1288 if ((p = getenv("SYSSCREENRC")))
1289 StartRc(p, 1);
1290 else
1291 # endif
1292 StartRc(ETCSCREENRC, 1);
1293 #endif
1294 StartRc(RcFileName, 1);
1295 if (InitTermcap(m->m.attach.columns, m->m.attach.lines))
1297 FreeDisplay();
1298 Kill(pid, SIG_BYE);
1299 return;
1301 MakeDefaultCanvas();
1302 InitTerm(m->m.attach.adaptflag); /* write init string on fd */
1303 if (displays->d_next == 0)
1304 (void) chsock();
1305 signal(SIGHUP, SigHup);
1306 if (m->m.attach.esc != -1 && m->m.attach.meta_esc != -1)
1308 D_user->u_Esc = m->m.attach.esc;
1309 D_user->u_MetaEsc = m->m.attach.meta_esc;
1312 #ifdef UTMPOK
1314 * we set the Utmp slots again, if we were detached normally
1315 * and if we were detached by ^Z.
1316 * don't log zomies back in!
1318 RemoveLoginSlot();
1319 if (displays->d_next == 0)
1320 for (wi = windows; wi; wi = wi->w_next)
1321 if (wi->w_ptyfd >= 0 && wi->w_slot != (slot_t) -1)
1322 SetUtmp(wi);
1323 #endif
1325 D_fore = NULL;
1326 if (layout_attach)
1328 struct layout *lay = layout_attach;
1329 if (lay == &layout_last_marker)
1330 lay = layout_last;
1331 if (lay)
1333 LoadLayout(lay, &D_canvas);
1334 SetCanvasWindow(D_forecv, 0);
1338 * there may be a window that we remember from last detach:
1340 debug1("D_user->u_detachwin = %d\n", D_user->u_detachwin);
1341 if (D_user->u_detachwin >= 0)
1342 fore = wtab[D_user->u_detachwin];
1343 else
1344 fore = 0;
1346 /* Wayne wants us to restore the other window too. */
1347 if (D_user->u_detachotherwin >= 0)
1348 D_other = wtab[D_user->u_detachotherwin];
1350 noshowwin = 0;
1351 if (*m->m.attach.preselect)
1353 if (!strcmp(m->m.attach.preselect, "="))
1354 fore = 0;
1355 else if (!strcmp(m->m.attach.preselect, "-"))
1357 fore = 0;
1358 noshowwin = 1;
1360 else if (!strcmp(m->m.attach.preselect, "+"))
1362 struct action newscreen;
1363 char *na = 0;
1364 newscreen.nr = RC_SCREEN;
1365 newscreen.args = &na;
1366 DoAction(&newscreen, -1);
1368 else
1369 fore = FindNiceWindow(fore, m->m.attach.preselect);
1371 else
1372 fore = FindNiceWindow(fore, 0);
1373 if (fore)
1374 SetForeWindow(fore);
1375 else if (!noshowwin)
1377 #ifdef MULTIUSER
1378 if (!AclCheckPermCmd(D_user, ACL_EXEC, &comms[RC_WINDOWLIST]))
1379 #endif
1381 flayer = D_forecv->c_layer;
1382 display_wlist(1, WLIST_NUM, (struct win *)0);
1383 noshowwin = 1;
1386 Activate(0);
1387 ResetIdle();
1388 if (!D_fore && !noshowwin)
1389 ShowWindows(-1);
1390 if (displays->d_next == 0 && console_window)
1392 if (TtyGrabConsole(console_window->w_ptyfd, 1, "reattach") == 0)
1393 Msg(0, "console %s is on window %d", HostName, console_window->w_number);
1395 debug("activated...\n");
1397 # if defined(DEBUG) && defined(SIG_NODEBUG)
1398 if (!dfp)
1400 sleep(1);
1401 debug1("Attacher %d must not debug, as we have debug off.\n", pid);
1402 kill(pid, SIG_NODEBUG);
1404 # endif /* SIG_NODEBUG */
1407 static void
1408 FinishDetach(m)
1409 struct msg *m;
1411 struct display *next, **d, *det;
1412 int pid;
1414 if (m->type == MSG_ATTACH)
1415 pid = D_userpid;
1416 else
1417 pid = m->m.detach.dpid;
1419 /* Remove the temporary display prompting for the password from the list */
1420 for (d = &displays; (det = *d); d = &det->d_next)
1422 if (det->d_userpid == pid)
1423 break;
1425 if (det)
1427 *d = det->d_next;
1428 det->d_next = 0;
1431 for (display = displays; display; display = next)
1433 next = display->d_next;
1434 # ifdef POW_DETACH
1435 if (m->type == MSG_POW_DETACH)
1436 Detach(D_REMOTE_POWER);
1437 else
1438 # endif /* POW_DETACH */
1439 if (m->type == MSG_DETACH)
1440 Detach(D_REMOTE);
1441 else if (m->type == MSG_ATTACH)
1443 #ifdef POW_DETACH
1444 if (m->m.attach.detachfirst == MSG_POW_DETACH)
1445 Detach(D_REMOTE_POWER);
1446 else
1447 #endif
1448 if (m->m.attach.detachfirst == MSG_DETACH)
1449 Detach(D_REMOTE);
1452 display = displays = det;
1453 if (m->type != MSG_ATTACH)
1455 if (display)
1456 FreeDisplay();
1457 Kill(pid, SIGCONT);
1461 #ifdef PASSWORD
1462 static void PasswordProcessInput __P((char *, int));
1464 struct pwdata {
1465 int l;
1466 char buf[20 + 1];
1467 struct msg m;
1470 static void
1471 AskPassword(m)
1472 struct msg *m;
1474 struct pwdata *pwdata;
1475 ASSERT(display);
1476 pwdata = (struct pwdata *)malloc(sizeof(struct pwdata));
1477 if (!pwdata)
1478 Panic(0, strnomem);
1479 pwdata->l = 0;
1480 pwdata->m = *m;
1481 D_processinputdata = (char *)pwdata;
1482 D_processinput = PasswordProcessInput;
1483 AddStr("Screen password: ");
1486 static void
1487 PasswordProcessInput(ibuf, ilen)
1488 char *ibuf;
1489 int ilen;
1491 struct pwdata *pwdata;
1492 int c, l;
1493 char *up;
1494 int pid = D_userpid;
1496 pwdata = (struct pwdata *)D_processinputdata;
1497 l = pwdata->l;
1498 while (ilen-- > 0)
1500 c = *(unsigned char *)ibuf++;
1501 if (c == '\r' || c == '\n')
1503 up = D_user->u_password;
1504 pwdata->buf[l] = 0;
1505 if (strncmp(crypt(pwdata->buf, up), up, strlen(up)))
1507 /* uh oh, user failed */
1508 bzero(pwdata->buf, sizeof(pwdata->buf));
1509 AddStr("\r\nPassword incorrect.\r\n");
1510 D_processinputdata = 0; /* otherwise freed by FreeDis */
1511 FreeDisplay();
1512 Msg(0, "Illegal reattach attempt from terminal %s.", pwdata->m.m_tty);
1513 free(pwdata);
1514 Kill(pid, SIG_BYE);
1515 return;
1517 /* great, pw matched, all is fine */
1518 bzero(pwdata->buf, sizeof(pwdata->buf));
1519 AddStr("\r\n");
1520 D_processinputdata = 0;
1521 D_processinput = ProcessInput;
1522 #ifdef REMOTE_DETACH
1523 if (pwdata->m.type == MSG_DETACH
1524 # ifdef POW_DETACH
1525 || pwdata->m.type == MSG_POW_DETACH
1526 # endif
1528 FinishDetach(&pwdata->m);
1529 else
1530 #endif
1531 FinishAttach(&pwdata->m);
1532 free(pwdata);
1533 return;
1535 if (c == Ctrl('c'))
1537 AddStr("\r\n");
1538 FreeDisplay();
1539 Kill(pid, SIG_BYE);
1540 return;
1542 if (c == '\b' || c == 0177)
1544 if (l > 0)
1545 l--;
1546 continue;
1548 if (c == Ctrl('u'))
1550 l = 0;
1551 continue;
1553 if (l < (int)sizeof(pwdata->buf) - 1)
1554 pwdata->buf[l++] = c;
1556 pwdata->l = l;
1558 #endif
1560 static void
1561 DoCommandMsg(mp)
1562 struct msg *mp;
1564 char *args[MAXARGS];
1565 int argl[MAXARGS];
1566 char fullcmd[MAXSTR];
1567 register char *fc;
1568 int n;
1569 register char *p = mp->m.command.cmd;
1570 struct acluser *user;
1571 #ifdef MULTIUSER
1572 extern struct acluser *EffectiveAclUser; /* acls.c */
1573 #else
1574 extern struct acluser *users; /* acls.c */
1575 #endif
1577 n = mp->m.command.nargs;
1578 if (n > MAXARGS - 1)
1579 n = MAXARGS - 1;
1580 for (fc = fullcmd; n > 0; n--)
1582 int len = strlen(p);
1583 strncpy(fc, p, fullcmd + sizeof(fullcmd) - fc - 1);
1584 p += len + 1;
1585 fc += len;
1586 *fc++ = ' ';
1588 if (fc != fullcmd)
1589 *--fc = 0;
1590 if (Parse(fullcmd, fc - fullcmd, args, argl) <= 0)
1591 return;
1592 #ifdef MULTIUSER
1593 user = *FindUserPtr(mp->m.attach.auser);
1594 if (user == 0)
1596 Msg(0, "Unknown user %s tried to send a command!", mp->m.attach.auser);
1597 return;
1599 #else
1600 user = users;
1601 #endif
1602 #ifdef PASSWORD
1603 if (user->u_password && *user->u_password)
1605 Msg(0, "User %s has a password, cannot use -X option.", mp->m.attach.auser);
1606 return;
1608 #endif
1609 if (!display)
1610 for (display = displays; display; display = display->d_next)
1611 if (D_user == user)
1612 break;
1613 for (fore = windows; fore; fore = fore->w_next)
1614 if (!TTYCMP(mp->m_tty, fore->w_tty))
1616 if (!display)
1617 display = fore->w_layer.l_cvlist ? fore->w_layer.l_cvlist->c_display : 0;
1618 break;
1620 if (!display)
1621 display = displays; /* sigh */
1622 if (*mp->m.command.preselect)
1624 int i = -1;
1625 if (strcmp(mp->m.command.preselect, "-"))
1626 i = WindowByNoN(mp->m.command.preselect);
1627 fore = i >= 0 ? wtab[i] : 0;
1629 else if (!fore)
1631 if (display && D_user == user)
1632 fore = Layer2Window(display->d_forecv->c_layer);
1633 if (!fore)
1635 fore = user->u_detachwin >= 0 ? wtab[user->u_detachwin] : 0;
1636 fore = FindNiceWindow(fore, 0);
1639 if (!fore)
1640 fore = windows; /* sigh */
1641 #ifdef MULTIUSER
1642 EffectiveAclUser = user;
1643 #endif
1644 if (*args)
1646 char *oldrcname = rc_name;
1647 rc_name = "-X";
1648 debug3("Running command on display %x window %x (%d)\n", display, fore, fore ? fore->w_number : -1);
1649 flayer = fore ? &fore->w_layer : 0;
1650 if (fore && fore->w_savelayer && (fore->w_blocked || fore->w_savelayer->l_cvlist == 0))
1651 flayer = fore->w_savelayer;
1652 DoCommand(args, argl);
1653 rc_name = oldrcname;
1655 #ifdef MULTIUSER
1656 EffectiveAclUser = 0;
1657 #endif
1660 #ifndef NAMEDPIPE
1663 SendAttachMsg(s, m, fd)
1664 int s;
1665 struct msg *m;
1666 int fd;
1668 int r;
1669 struct msghdr msg;
1670 struct iovec iov;
1671 char buf[CMSG_SPACE(sizeof(int))];
1672 struct cmsghdr *cmsg;
1674 iov.iov_base = (char *)m;
1675 iov.iov_len = sizeof(*m);
1676 bzero(&msg, sizeof(msg));
1677 msg.msg_name = 0;
1678 msg.msg_namelen = 0;
1679 msg.msg_iov = &iov;
1680 msg.msg_iovlen = 1;
1681 msg.msg_control = buf;
1682 msg.msg_controllen = sizeof(buf);
1683 cmsg = CMSG_FIRSTHDR(&msg);
1684 cmsg->cmsg_level = SOL_SOCKET;
1685 cmsg->cmsg_type = SCM_RIGHTS;
1686 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
1687 bcopy(&fd, CMSG_DATA(cmsg), sizeof(int));
1688 msg.msg_controllen = cmsg->cmsg_len;
1689 while(1)
1691 r = sendmsg(s, &msg, 0);
1692 if (r == -1 && errno == EINTR)
1693 continue;
1694 if (r == -1)
1695 return -1;
1696 return 0;
1700 #endif