Start converting to GPL v3+ (ref: ticket #23900)
[screen-lua.git] / src / socket.c
blobb9614711108fe6698e09a66bd1b9cc764422c9e4
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 3, 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, see
18 * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 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 FinishDetach __P((struct msg *));
57 static void AskPassword __P((struct msg *));
60 extern char *RcFileName, *extra_incap, *extra_outcap;
61 extern int ServerSocket, real_uid, real_gid, eff_uid, eff_gid;
62 extern int dflag, iflag, rflag, lsflag, quietflag, wipeflag, xflag;
63 extern char *attach_tty, *LoginName, HostName[];
64 extern struct display *display, *displays;
65 extern struct win *fore, *wtab[], *console_window, *windows;
66 extern struct layer *flayer;
67 extern struct layout *layout_attach, *layout_last, layout_last_marker;
68 extern struct NewWindow nwin_undef;
69 #ifdef MULTIUSER
70 extern char *multi;
71 #endif
73 extern char *getenv();
75 extern char SockPath[];
76 extern struct event serv_read;
77 extern char *rc_name;
78 extern struct comm comms[];
80 #ifdef MULTIUSER
81 # define SOCKMODE (S_IWRITE | S_IREAD | (displays ? S_IEXEC : 0) | (multi ? 1 : 0))
82 #else
83 # define SOCKMODE (S_IWRITE | S_IREAD | (displays ? S_IEXEC : 0))
84 #endif
88 * Socket directory manager
90 * fdp: pointer to store the first good socket.
91 * nfoundp: pointer to store the number of sockets found matching.
92 * notherp: pointer to store the number of sockets not matching.
93 * match: string to match socket name.
95 * The socket directory must be in SockPath!
96 * The global variables LoginName, multi, rflag, xflag, dflag,
97 * quietflag, SockPath are used.
99 * The first good socket is stored in fdp and its name is
100 * appended to SockPath.
101 * If none exists or fdp is NULL SockPath is not changed.
103 * Returns: number of good sockets.
108 FindSocket(fdp, nfoundp, notherp, match)
109 int *fdp;
110 int *nfoundp, *notherp;
111 char *match;
113 DIR *dirp;
114 struct dirent *dp;
115 struct stat st;
116 int mode;
117 int sdirlen;
118 int matchlen = 0;
119 char *name, *n;
120 int firsts = -1, sockfd;
121 char *firstn = NULL;
122 int nfound = 0, ngood = 0, ndead = 0, nwipe = 0, npriv = 0;
123 int nperfect = 0;
124 struct sent
126 struct sent *next;
127 int mode;
128 char *name;
129 } *slist, **slisttail, *sent, *nsent;
131 if (match)
133 matchlen = strlen(match);
134 #ifdef NAME_MAX
135 if (matchlen > NAME_MAX)
136 matchlen = NAME_MAX;
137 #endif
141 * SockPath contains the socket directory.
142 * At the end of FindSocket the socket name will be appended to it.
143 * Thus FindSocket() can only be called once!
145 sdirlen = strlen(SockPath);
147 #ifdef USE_SETEUID
148 xseteuid(real_uid);
149 xsetegid(real_gid);
150 #endif
152 if ((dirp = opendir(SockPath)) == 0)
153 Panic(errno, "Cannot opendir %s", SockPath);
155 slist = 0;
156 slisttail = &slist;
157 while ((dp = readdir(dirp)))
159 int cmatch = 0;
160 name = dp->d_name;
161 debug1("- %s\n", name);
162 if (*name == 0 || *name == '.' || strlen(name) > 2*MAXSTR)
163 continue;
164 if (matchlen)
166 n = name;
167 /* if we don't want to match digits. Skip them */
168 if ((*match <= '0' || *match > '9') && (*n > '0' && *n <= '9'))
170 while (*n >= '0' && *n <= '9')
171 n++;
172 if (*n == '.')
173 n++;
175 /* the tty prefix is optional */
176 if (strncmp(match, "tty", 3) && strncmp(n, "tty", 3) == 0)
177 n += 3;
178 if (strncmp(match, n, matchlen))
179 continue;
180 cmatch = (*(n + matchlen) == 0);
181 debug1(" -> matched %s\n", match);
183 sprintf(SockPath + sdirlen, "/%s", name);
185 debug1("stat %s\n", SockPath);
186 errno = 0;
187 debug2("uid = %d, gid = %d\n", getuid(), getgid());
188 debug2("euid = %d, egid = %d\n", geteuid(), getegid());
189 if (stat(SockPath, &st))
191 debug1("errno = %d\n", errno);
192 continue;
195 #ifndef SOCK_NOT_IN_FS
196 # ifdef NAMEDPIPE
197 # ifdef S_ISFIFO
198 debug("S_ISFIFO?\n");
199 if (!S_ISFIFO(st.st_mode))
200 continue;
201 # endif
202 # else
203 # ifdef S_ISSOCK
204 debug("S_ISSOCK?\n");
205 if (!S_ISSOCK(st.st_mode))
206 continue;
207 # endif
208 # endif
209 #endif
211 debug2("st.st_uid = %d, real_uid = %d\n", st.st_uid, real_uid);
212 if ((int)st.st_uid != real_uid)
213 continue;
214 mode = (int)st.st_mode & 0777;
215 debug1(" has mode 0%03o\n", mode);
216 #ifdef MULTIUSER
217 if (multi && ((mode & 0677) != 0601))
219 debug(" is not a MULTI-USER session");
220 if (strcmp(multi, LoginName))
222 debug(" and we are in a foreign directory.\n");
223 mode = -4;
225 else
227 debug(", but it is our own session.\n");
230 #endif
231 debug(" store it.\n");
232 if ((sent = (struct sent *)malloc(sizeof(struct sent))) == 0)
233 continue;
234 sent->next = 0;
235 sent->name = SaveStr(name);
236 sent->mode = mode;
237 *slisttail = sent;
238 slisttail = &sent->next;
239 nfound++;
240 sockfd = MakeClientSocket(0);
241 #ifdef USE_SETEUID
242 /* MakeClientSocket sets ids back to eff */
243 xseteuid(real_uid);
244 xsetegid(real_gid);
245 #endif
246 if (sockfd == -1)
248 debug2(" MakeClientSocket failed, unreachable? %d %d\n",
249 matchlen, wipeflag);
250 sent->mode = -3;
251 #ifndef SOCKDIR_IS_LOCAL_TO_HOST
252 /* Unreachable - it is dead if we detect that it's local
253 * or we specified a match
255 n = name + strlen(name) - 1;
256 while (n != name && *n != '.')
257 n--;
258 if (matchlen == 0 && !(*n == '.' && n[1] && strncmp(HostName, n + 1, strlen(n + 1)) == 0))
260 npriv++; /* a good socket that was not for us */
261 continue;
263 #endif
264 ndead++;
265 sent->mode = -1;
266 if (wipeflag)
268 if (unlink(SockPath) == 0)
270 sent->mode = -2;
271 nwipe++;
274 continue;
277 mode &= 0776;
278 /* Shall we connect ? */
279 debug2(" connecting: mode=%03o, rflag=%d, ", mode, rflag);
280 debug2("xflag=%d, dflag=%d ?\n", xflag, dflag);
283 * mode 600: socket is detached.
284 * mode 700: socket is attached.
285 * xflag implies rflag here.
287 * fail, when socket mode mode is not 600 or 700
288 * fail, when we want to detach w/o reattach, but it already is detached.
289 * fail, when we only want to attach, but mode 700 and not xflag.
290 * fail, if none of dflag, rflag, xflag is set.
292 if ((mode != 0700 && mode != 0600) ||
293 (dflag && !rflag && !xflag && mode == 0600) ||
294 (!dflag && rflag && mode == 0700 && !xflag) ||
295 (!dflag && !rflag && !xflag))
297 close(sockfd);
298 debug(" no!\n");
299 npriv++; /* a good socket that was not for us */
300 continue;
302 ngood++;
303 if (cmatch)
304 nperfect++;
305 if (fdp && (firsts == -1 || (cmatch && nperfect == 1)))
307 if (firsts != -1)
308 close(firsts);
309 firsts = sockfd;
310 firstn = sent->name;
311 debug(" taken.\n");
313 else
315 debug(" discarded.\n");
316 close(sockfd);
319 (void)closedir(dirp);
320 if (!lsflag && nperfect == 1)
321 ngood = nperfect;
322 if (nfound && (lsflag || ngood != 1) && !quietflag)
324 switch(ngood)
326 case 0:
327 Msg(0, nfound > 1 ? "There are screens on:" : "There is a screen on:");
328 break;
329 case 1:
330 Msg(0, nfound > 1 ? "There are several screens on:" : "There is a suitable screen on:");
331 break;
332 default:
333 Msg(0, "There are several suitable screens on:");
334 break;
336 for (sent = slist; sent; sent = sent->next)
338 switch (sent->mode)
340 case 0700:
341 printf("\t%s\t(Attached)\n", sent->name);
342 break;
343 case 0600:
344 printf("\t%s\t(Detached)\n", sent->name);
345 break;
346 #ifdef MULTIUSER
347 case 0701:
348 printf("\t%s\t(Multi, attached)\n", sent->name);
349 break;
350 case 0601:
351 printf("\t%s\t(Multi, detached)\n", sent->name);
352 break;
353 #endif
354 case -1:
355 /* No trigraphs here! */
356 printf("\t%s\t(Dead ?%c?)\n", sent->name, '?');
357 break;
358 case -2:
359 printf("\t%s\t(Removed)\n", sent->name);
360 break;
361 case -3:
362 printf("\t%s\t(Remote or dead)\n", sent->name);
363 break;
364 case -4:
365 printf("\t%s\t(Private)\n", sent->name);
366 break;
370 if (ndead && !quietflag)
372 char *m = "Remove dead screens with 'screen -wipe'.";
373 if (wipeflag)
374 Msg(0, "%d socket%s wiped out.", nwipe, nwipe > 1 ? "s" : "");
375 else
376 Msg(0, m, ndead > 1 ? "s" : "", ndead > 1 ? "" : "es"); /* other args for nethack */
378 if (firsts != -1)
380 sprintf(SockPath + sdirlen, "/%s", firstn);
381 *fdp = firsts;
383 else
384 SockPath[sdirlen] = 0;
385 for (sent = slist; sent; sent = nsent)
387 nsent = sent->next;
388 free(sent->name);
389 free((char *)sent);
391 #ifdef USE_SETEUID
392 xseteuid(eff_uid);
393 xsetegid(eff_gid);
394 #endif
395 if (notherp)
396 *notherp = npriv;
397 if (nfoundp)
398 *nfoundp = nfound - nwipe;
399 return ngood;
405 ** Socket/pipe create routines
409 #ifdef NAMEDPIPE
412 MakeServerSocket()
414 register int s;
415 struct stat st;
417 # ifdef USE_SETEUID
418 xseteuid(real_uid);
419 xsetegid(real_gid);
420 # endif
421 if ((s = open(SockPath, O_WRONLY | O_NONBLOCK)) >= 0)
423 debug("huii, my fifo already exists??\n");
424 if (quietflag)
426 Kill(D_userpid, SIG_BYE);
427 eexit(11);
429 Msg(0, "There is already a screen running on %s.", Filename(SockPath));
430 if (stat(SockPath, &st) == -1)
431 Panic(errno, "stat");
432 if ((int)st.st_uid != real_uid)
433 Panic(0, "Unfortunatelly you are not its owner.");
434 if ((st.st_mode & 0700) == 0600)
435 Panic(0, "To resume it, use \"screen -r\"");
436 else
437 Panic(0, "It is not detached.");
438 /* NOTREACHED */
440 # ifdef USE_SETEUID
441 (void) unlink(SockPath);
442 if (mkfifo(SockPath, SOCKMODE))
443 Panic(0, "mkfifo %s failed", SockPath);
444 # ifdef BROKEN_PIPE
445 if ((s = open(SockPath, O_RDWR | O_NONBLOCK, 0)) < 0)
446 # else
447 if ((s = open(SockPath, O_RDONLY | O_NONBLOCK, 0)) < 0)
448 # endif
449 Panic(errno, "open fifo %s", SockPath);
450 xseteuid(eff_uid);
451 xsetegid(eff_gid);
452 return s;
453 # else /* !USE_SETEUID */
454 if (UserContext() > 0)
456 (void) unlink(SockPath);
457 UserReturn(mkfifo(SockPath, SOCKMODE));
459 if (UserStatus())
460 Panic(0, "mkfifo %s failed", SockPath);
461 # ifdef BROKEN_PIPE
462 if ((s = secopen(SockPath, O_RDWR | O_NONBLOCK, 0)) < 0)
463 # else
464 if ((s = secopen(SockPath, O_RDONLY | O_NONBLOCK, 0)) < 0)
465 # endif
466 Panic(errno, "open fifo %s", SockPath);
467 return s;
468 # endif /* !USE_SETEUID */
473 MakeClientSocket(err)
474 int err;
476 register int s = 0;
478 if ((s = secopen(SockPath, O_WRONLY | O_NONBLOCK, 0)) >= 0)
480 (void) fcntl(s, F_SETFL, 0);
481 return s;
483 if (err)
484 Msg(errno, "%s", SockPath);
485 debug2("MakeClientSocket() open %s failed (%d)\n", SockPath, errno);
486 return -1;
490 #else /* NAMEDPIPE */
494 MakeServerSocket()
496 register int s;
497 struct sockaddr_un a;
498 struct stat st;
500 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
501 Panic(errno, "socket");
502 a.sun_family = AF_UNIX;
503 strncpy(a.sun_path, SockPath, sizeof(a.sun_path));
504 a.sun_path[sizeof(a.sun_path) - 1] = 0;
505 # ifdef USE_SETEUID
506 xseteuid(real_uid);
507 xsetegid(real_gid);
508 # endif
509 if (connect(s, (struct sockaddr *) &a, strlen(SockPath) + 2) != -1)
511 debug("oooooh! socket already is alive!\n");
512 if (quietflag)
514 Kill(D_userpid, SIG_BYE);
516 * oh, well. nobody receives that return code. papa
517 * dies by signal.
519 eexit(11);
521 Msg(0, "There is already a screen running on %s.", Filename(SockPath));
522 if (stat(SockPath, &st) == -1)
523 Panic(errno, "stat");
524 if (st.st_uid != real_uid)
525 Panic(0, "Unfortunatelly you are not its owner.");
526 if ((st.st_mode & 0700) == 0600)
527 Panic(0, "To resume it, use \"screen -r\"");
528 else
529 Panic(0, "It is not detached.");
530 /* NOTREACHED */
532 #if defined(m88k) || defined(sysV68)
533 close(s); /* we get bind: Invalid argument if this is not done */
534 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
535 Panic(errno, "reopen socket");
536 #endif
537 (void) unlink(SockPath);
538 if (bind(s, (struct sockaddr *) & a, strlen(SockPath) + 2) == -1)
539 Panic(errno, "bind (%s)", SockPath);
540 #ifdef SOCK_NOT_IN_FS
542 int f;
543 if ((f = secopen(SockPath, O_RDWR | O_CREAT, SOCKMODE)) < 0)
544 Panic(errno, "shadow socket open");
545 close(f);
547 #else
548 chmod(SockPath, SOCKMODE);
549 # ifndef USE_SETEUID
550 chown(SockPath, real_uid, real_gid);
551 # endif
552 #endif /* SOCK_NOT_IN_FS */
553 if (listen(s, 5) == -1)
554 Panic(errno, "listen");
555 # ifdef F_SETOWN
556 fcntl(s, F_SETOWN, getpid());
557 debug1("Serversocket owned by %d\n", fcntl(s, F_GETOWN, 0));
558 # endif /* F_SETOWN */
559 # ifdef USE_SETEUID
560 xseteuid(eff_uid);
561 xsetegid(eff_gid);
562 # endif
563 return s;
567 MakeClientSocket(err)
568 int err;
570 register int s;
571 struct sockaddr_un a;
573 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
574 Panic(errno, "socket");
575 a.sun_family = AF_UNIX;
576 strncpy(a.sun_path, SockPath, sizeof(a.sun_path));
577 a.sun_path[sizeof(a.sun_path) - 1] = 0;
578 # ifdef USE_SETEUID
579 xseteuid(real_uid);
580 xsetegid(real_gid);
581 # else
582 if (access(SockPath, W_OK))
584 if (err)
585 Msg(errno, "%s", SockPath);
586 debug2("MakeClientSocket: access(%s): %d.\n", SockPath, errno);
587 close(s);
588 return -1;
590 # endif
591 if (connect(s, (struct sockaddr *) &a, strlen(SockPath) + 2) == -1)
593 if (err)
594 Msg(errno, "%s: connect", SockPath);
595 debug("MakeClientSocket: connect failed.\n");
596 close(s);
597 s = -1;
599 # ifdef USE_SETEUID
600 xseteuid(eff_uid);
601 xsetegid(eff_gid);
602 # endif
603 return s;
605 #endif /* NAMEDPIPE */
610 ** Message send and receive routines
614 void
615 SendCreateMsg(sty, nwin)
616 char *sty;
617 struct NewWindow *nwin;
619 int s;
620 struct msg m;
621 register char *p;
622 register int len, n;
623 char **av = nwin->args;
625 #ifdef NAME_MAX
626 if (strlen(sty) > NAME_MAX)
627 sty[NAME_MAX] = 0;
628 #endif
629 if (strlen(sty) > 2 * MAXSTR - 1)
630 sty[2 * MAXSTR - 1] = 0;
631 sprintf(SockPath + strlen(SockPath), "/%s", sty);
632 if ((s = MakeClientSocket(1)) == -1)
633 exit(1);
634 debug1("SendCreateMsg() to '%s'\n", SockPath);
635 bzero((char *)&m, sizeof(m));
636 m.type = MSG_CREATE;
637 strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1);
638 m.m_tty[sizeof(m.m_tty) - 1] = 0;
639 p = m.m.create.line;
640 n = 0;
641 if (nwin->args != nwin_undef.args)
642 for (av = nwin->args; *av && n < MAXARGS - 1; ++av, ++n)
644 len = strlen(*av) + 1;
645 if (p + len >= m.m.create.line + sizeof(m.m.create.line) - 1)
646 break;
647 strcpy(p, *av);
648 p += len;
650 if (nwin->aka != nwin_undef.aka && p + strlen(nwin->aka) + 1 < m.m.create.line + sizeof(m.m.create.line))
651 strcpy(p, nwin->aka);
652 else
653 *p = '\0';
654 m.m.create.nargs = n;
655 m.m.create.aflag = nwin->aflag;
656 m.m.create.flowflag = nwin->flowflag;
657 m.m.create.lflag = nwin->lflag;
658 m.m.create.hheight = nwin->histheight;
659 if (getcwd(m.m.create.dir, sizeof(m.m.create.dir)) == 0)
661 Msg(errno, "getcwd");
662 return;
664 if (nwin->term != nwin_undef.term)
665 strncpy(m.m.create.screenterm, nwin->term, 19);
666 m.m.create.screenterm[19] = '\0';
667 m.protocol_revision = MSG_REVISION;
668 debug1("SendCreateMsg writing '%s'\n", m.m.create.line);
669 if (write(s, (char *) &m, sizeof m) != sizeof m)
670 Msg(errno, "write");
671 close(s);
675 SendErrorMsg(tty, buf)
676 char *tty, *buf;
678 int s;
679 struct msg m;
681 strncpy(m.m.message, buf, sizeof(m.m.message) - 1);
682 m.m.message[sizeof(m.m.message) - 1] = 0;
683 s = MakeClientSocket(0);
684 if (s < 0)
685 return -1;
686 m.type = MSG_ERROR;
687 strncpy(m.m_tty, tty, sizeof(m.m_tty) - 1);
688 m.m_tty[sizeof(m.m_tty) - 1] = 0;
689 m.protocol_revision = MSG_REVISION;
690 debug1("SendErrorMsg(): writing to '%s'\n", SockPath);
691 (void) write(s, (char *) &m, sizeof m);
692 close(s);
693 return 0;
696 static void
697 ExecCreate(mp)
698 struct msg *mp;
700 struct NewWindow nwin;
701 char *args[MAXARGS];
702 register int n;
703 register char **pp = args, *p = mp->m.create.line;
705 nwin = nwin_undef;
706 n = mp->m.create.nargs;
707 if (n > MAXARGS - 1)
708 n = MAXARGS - 1;
709 /* ugly hack alert... should be done by the frontend! */
710 if (n)
712 int l, num;
713 char buf[20];
715 l = strlen(p);
716 if (IsNumColon(p, 10, buf, sizeof(buf)))
718 if (*buf)
719 nwin.aka = buf;
720 num = atoi(p);
721 if (num < 0 || num > MAXWIN - 1)
722 num = 0;
723 nwin.StartAt = num;
724 p += l + 1;
725 n--;
728 for (; n > 0; n--)
730 *pp++ = p;
731 p += strlen(p) + 1;
733 *pp = 0;
734 if (*p)
735 nwin.aka = p;
736 if (*args)
737 nwin.args = args;
738 nwin.aflag = mp->m.create.aflag;
739 nwin.flowflag = mp->m.create.flowflag;
740 if (*mp->m.create.dir)
741 nwin.dir = mp->m.create.dir;
742 nwin.lflag = mp->m.create.lflag;
743 nwin.histheight = mp->m.create.hheight;
744 if (*mp->m.create.screenterm)
745 nwin.term = mp->m.create.screenterm;
746 MakeWindow(&nwin);
749 static int
750 CheckPid(pid)
751 int pid;
753 debug1("Checking pid %d\n", pid);
754 if (pid < 2)
755 return -1;
756 if (eff_uid == real_uid)
757 return kill(pid, 0);
758 if (UserContext() > 0)
759 UserReturn(kill(pid, 0));
760 return UserStatus();
763 #ifdef hpux
765 * From: "F. K. Bruner" <napalm@ugcs.caltech.edu>
766 * From: "Dan Egnor" <egnor@oracorp.com> Tue Aug 10 06:56:45 1993
767 * The problem is that under HPUX (and possibly other systems too) there are
768 * two equivalent device files for each pty/tty device:
769 * /dev/ttyxx == /dev/pty/ttyxx
770 * /dev/ptyxx == /dev/ptym/ptyxx
771 * I didn't look into the exact specifics, but I've run across this problem
772 * before: Even if you open /dev/ttyxx as fds 0 1 & 2 for a process, if that
773 * process calls the system to determine its tty, it'll get /dev/pty/ttyxx.
775 * Earlier versions seemed to work -- wonder what they did.
777 static int
778 ttycmp(s1, s2)
779 char *s1, *s2;
781 if (strlen(s1) > 5) s1 += strlen(s1) - 5;
782 if (strlen(s2) > 5) s2 += strlen(s2) - 5;
783 return strcmp(s1, s2);
785 # define TTYCMP(a, b) ttycmp(a, b)
786 #else
787 # define TTYCMP(a, b) strcmp(a, b)
788 #endif
790 static int
791 CreateTempDisplay(m, recvfd, wi)
792 struct msg *m;
793 int recvfd;
794 struct win *wi;
796 int pid;
797 int attach;
798 char *user;
799 int i;
800 struct mode Mode;
801 struct display *olddisplays = displays;
803 switch (m->type)
805 case MSG_CONT:
806 case MSG_ATTACH:
807 pid = m->m.attach.apid;
808 user = m->m.attach.auser;
809 attach = 1;
810 break;
811 #ifdef REMOTE_DETACH
812 case MSG_DETACH:
813 # ifdef POW_DETACH
814 case MSG_POW_DETACH:
815 # endif /* POW_DETACH */
816 pid = m->m.detach.dpid;
817 user = m->m.detach.duser;
818 attach = 0;
819 break;
820 #endif
821 default:
822 return -1;
825 if (CheckPid(pid))
827 Msg(0, "Attach attempt with bad pid(%d)!", pid);
828 return -1;
830 if (recvfd != -1)
832 char *myttyname;
833 i = recvfd;
834 recvfd = -1;
835 myttyname = ttyname(i);
836 if (myttyname == 0 || strcmp(myttyname, m->m_tty))
838 Msg(errno, "Attach: passed fd does not match tty: %s - %s!", m->m_tty, myttyname ? myttyname : "NULL");
839 close(i);
840 Kill(pid, SIG_BYE);
841 return -1;
844 else if ((i = secopen(m->m_tty, O_RDWR | O_NONBLOCK, 0)) < 0)
846 Msg(errno, "Attach: Could not open %s!", m->m_tty);
847 Kill(pid, SIG_BYE);
848 return -1;
850 #ifdef MULTIUSER
851 if (attach)
852 Kill(pid, SIGCONT);
853 #endif
855 #if defined(ultrix) || defined(pyr) || defined(NeXT)
856 brktty(i); /* for some strange reason this must be done */
857 #endif
859 if (attach)
861 if (display || wi)
863 write(i, "Attaching from inside of screen?\n", 33);
864 close(i);
865 Kill(pid, SIG_BYE);
866 Msg(0, "Attach msg ignored: coming from inside.");
867 return -1;
870 #ifdef MULTIUSER
871 if (strcmp(user, LoginName))
872 if (*FindUserPtr(user) == 0)
874 write(i, "Access to session denied.\n", 26);
875 close(i);
876 Kill(pid, SIG_BYE);
877 Msg(0, "Attach: access denied for user %s.", user);
878 return -1;
880 #endif
882 debug2("RecMsg: apid %d is o.k. and we just opened '%s'\n", pid, m->m_tty);
883 #ifndef MULTI
884 if (displays)
886 write(i, "Screen session in use.\n", 23);
887 close(i);
888 Kill(pid, SIG_BYE);
889 return -1;
891 #endif
894 /* create new display */
895 GetTTY(i, &Mode);
896 if (MakeDisplay(user, m->m_tty, attach ? m->m.attach.envterm : "", i, pid, &Mode) == 0)
898 write(i, "Could not make display.\n", 24);
899 close(i);
900 Msg(0, "Attach: could not make display for user %s", user);
901 Kill(pid, SIG_BYE);
902 return -1;
904 #ifdef ENCODINGS
905 if (attach)
907 # ifdef UTF8
908 D_encoding = m->m.attach.encoding == 1 ? UTF8 : m->m.attach.encoding ? m->m.attach.encoding - 1 : 0;
909 # else
910 D_encoding = m->m.attach.encoding ? m->m.attach.encoding - 1 : 0;
911 # endif
912 if (D_encoding < 0 || !EncodingName(D_encoding))
913 D_encoding = 0;
914 #endif
917 if (iflag && olddisplays)
919 iflag = 0;
920 #if defined(TERMIO) || defined(POSIX)
921 olddisplays->d_NewMode.tio.c_cc[VINTR] = VDISABLE;
922 olddisplays->d_NewMode.tio.c_lflag &= ~ISIG;
923 #else /* TERMIO || POSIX */
924 olddisplays->d_NewMode.m_tchars.t_intrc = -1;
925 #endif /* TERMIO || POSIX */
926 SetTTY(olddisplays->d_userfd, &olddisplays->d_NewMode);
928 SetMode(&D_OldMode, &D_NewMode, D_flow, iflag);
929 SetTTY(D_userfd, &D_NewMode);
930 if (fcntl(D_userfd, F_SETFL, FNBLOCK))
931 Msg(errno, "Warning: NBLOCK fcntl failed");
932 return 0;
935 void
936 ReceiveMsg()
938 int left, len;
939 static struct msg m;
940 char *p;
941 int ns = ServerSocket;
942 struct win *wi;
943 int recvfd = -1;
944 struct acluser *user;
946 #ifdef NAMEDPIPE
947 debug("Ha, there was someone knocking on my fifo??\n");
948 if (fcntl(ServerSocket, F_SETFL, 0) == -1)
949 Panic(errno, "BLOCK fcntl");
950 p = (char *) &m;
951 left = sizeof(m);
952 #else
953 struct sockaddr_un a;
954 struct msghdr msg;
955 struct iovec iov;
956 char control[1024];
958 len = sizeof(a);
959 debug("Ha, there was someone knocking on my socket??\n");
960 if ((ns = accept(ns, (struct sockaddr *) &a, (void *)&len)) < 0)
962 Msg(errno, "accept");
963 return;
966 p = (char *) &m;
967 left = sizeof(m);
968 bzero(&msg, sizeof(msg));
969 iov.iov_base = &m;
970 iov.iov_len = left;
971 msg.msg_iov = &iov;
972 msg.msg_iovlen = 1;
973 msg.msg_controllen = sizeof(control);
974 msg.msg_control = &control;
975 while (left > 0)
977 len = recvmsg(ns, &msg, 0);
978 if (len < 0 && errno == EINTR)
979 continue;
980 if (len < 0)
982 close(ns);
983 Msg(errno, "read");
984 return;
986 if (msg.msg_controllen)
988 struct cmsghdr *cmsg;
989 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
991 int cl;
992 char *cp;
993 if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS)
994 continue;
995 cp = (char *)CMSG_DATA(cmsg);
996 cl = cmsg->cmsg_len;
997 while(cl >= CMSG_LEN(sizeof(int)))
999 int passedfd;
1000 bcopy(cp, &passedfd, sizeof(int));
1001 if (recvfd >= 0 && passedfd != recvfd)
1002 close(recvfd);
1003 recvfd = passedfd;
1004 cl -= CMSG_LEN(sizeof(int));
1008 p += len;
1009 left -= len;
1010 break;
1013 #endif
1015 while (left > 0)
1017 len = read(ns, p, left);
1018 if (len < 0 && errno == EINTR)
1019 continue;
1020 if (len <= 0)
1021 break;
1022 p += len;
1023 left -= len;
1026 #ifdef NAMEDPIPE
1027 # ifndef BROKEN_PIPE
1028 /* Reopen pipe to prevent EOFs at the select() call */
1029 close(ServerSocket);
1030 if ((ServerSocket = secopen(SockPath, O_RDONLY | O_NONBLOCK, 0)) < 0)
1031 Panic(errno, "reopen fifo %s", SockPath);
1032 evdeq(&serv_read);
1033 serv_read.fd = ServerSocket;
1034 evenq(&serv_read);
1035 # endif
1036 #else
1037 close(ns);
1038 #endif
1040 if (len < 0)
1042 Msg(errno, "read");
1043 if (recvfd != -1)
1044 close(recvfd);
1045 return;
1047 if (left > 0)
1049 if (left != sizeof(m))
1050 Msg(0, "Message %d of %d bytes too small", left, (int)sizeof(m));
1051 else
1052 debug("No data on socket.\n");
1053 return;
1055 if (m.protocol_revision != MSG_REVISION)
1057 if (recvfd != -1)
1058 close(recvfd);
1059 Msg(0, "Invalid message (magic 0x%08x).", m.protocol_revision);
1060 return;
1063 debug2("*** RecMsg: type %d tty %s\n", m.type, m.m_tty);
1064 if (m.type != MSG_ATTACH && recvfd != -1)
1066 close(recvfd);
1067 recvfd = -1;
1070 for (display = displays; display; display = display->d_next)
1071 if (TTYCMP(D_usertty, m.m_tty) == 0)
1072 break;
1073 debug2("display: %s display %sfound\n", m.m_tty, display ? "" : "not ");
1074 wi = 0;
1075 if (!display)
1077 for (wi = windows; wi; wi = wi->w_next)
1078 if (!TTYCMP(m.m_tty, wi->w_tty))
1080 /* XXX: hmmm, rework this? */
1081 display = wi->w_layer.l_cvlist ? wi->w_layer.l_cvlist->c_display : 0;
1082 debug2("but window %s %sfound.\n", m.m_tty, display ? "" :
1083 "(backfacing)");
1084 break;
1088 /* Remove the status to prevent garbage on the screen */
1089 if (display && D_status)
1090 RemoveStatus();
1092 if (display && !D_tcinited && m.type != MSG_HANGUP)
1094 if (recvfd != -1)
1095 close(recvfd);
1096 return; /* ignore messages for bad displays */
1099 switch (m.type)
1101 case MSG_WINCH:
1102 if (display)
1103 CheckScreenSize(1); /* Change fore */
1104 break;
1105 case MSG_CREATE:
1107 * the window that issued the create message need not be an active
1108 * window. Then we create the window without having a display.
1109 * Resulting in another inactive window.
1111 ExecCreate(&m);
1112 break;
1113 case MSG_CONT:
1114 if (display && D_userpid != 0 && kill(D_userpid, 0) == 0)
1115 break; /* Intruder Alert */
1116 debug2("RecMsg: apid=%d,was %d\n", m.m.attach.apid, display ? D_userpid : 0);
1117 /* FALLTHROUGH */
1119 case MSG_ATTACH:
1120 if (CreateTempDisplay(&m, recvfd, wi))
1121 break;
1122 #ifdef PASSWORD
1123 if (D_user->u_password && *D_user->u_password)
1124 AskPassword(&m);
1125 else
1126 #endif
1127 FinishAttach(&m);
1128 break;
1129 case MSG_ERROR:
1130 Msg(0, "%s", m.m.message);
1131 break;
1132 case MSG_HANGUP:
1133 if (!wi) /* ignore hangups from inside */
1134 Hangup();
1135 break;
1136 #ifdef REMOTE_DETACH
1137 case MSG_DETACH:
1138 # ifdef POW_DETACH
1139 case MSG_POW_DETACH:
1140 # endif /* POW_DETACH */
1141 #ifdef PASSWORD
1142 user = *FindUserPtr(m.m.detach.duser);
1143 if (user && user->u_password && *user->u_password)
1145 if (CreateTempDisplay(&m, recvfd, 0))
1146 break;
1147 AskPassword(&m);
1149 else
1150 #endif /* PASSWORD */
1151 FinishDetach(&m);
1152 break;
1153 #endif
1154 case MSG_COMMAND:
1155 DoCommandMsg(&m);
1156 break;
1157 default:
1158 Msg(0, "Invalid message (type %d).", m.type);
1162 #if defined(_SEQUENT_) && !defined(NAMEDPIPE)
1163 #undef connect
1165 * sequent_ptx socket emulation must have mode 000 on the socket!
1167 static int
1168 sconnect(s, sapp, len)
1169 int s, len;
1170 struct sockaddr *sapp;
1172 register struct sockaddr_un *sap;
1173 struct stat st;
1174 int x;
1176 sap = (struct sockaddr_un *)sapp;
1177 if (stat(sap->sun_path, &st))
1178 return -1;
1179 chmod(sap->sun_path, 0);
1180 x = connect(s, (struct sockaddr *) sap, len);
1181 chmod(sap->sun_path, st.st_mode);
1182 return x;
1184 #endif
1188 * Set the mode bits of the socket to the current status
1191 chsock()
1193 int r, euid = geteuid();
1194 if (euid != real_uid)
1196 if (UserContext() <= 0)
1197 return UserStatus();
1199 r = chmod(SockPath, SOCKMODE);
1201 * Sockets usually reside in the /tmp/ area, where sysadmin scripts
1202 * may be happy to remove old files. We manually prevent the socket
1203 * from becoming old. (chmod does not touch mtime).
1205 (void)utimes(SockPath, NULL);
1207 if (euid != real_uid)
1208 UserReturn(r);
1209 return r;
1213 * Try to recreate the socket/pipe
1216 RecoverSocket()
1218 close(ServerSocket);
1219 if ((int)geteuid() != real_uid)
1221 if (UserContext() > 0)
1222 UserReturn(unlink(SockPath));
1223 (void)UserStatus();
1225 else
1226 (void) unlink(SockPath);
1228 if ((ServerSocket = MakeServerSocket()) < 0)
1229 return 0;
1230 evdeq(&serv_read);
1231 serv_read.fd = ServerSocket;
1232 evenq(&serv_read);
1233 return 1;
1237 static void
1238 FinishAttach(m)
1239 struct msg *m;
1241 char *p;
1242 int pid;
1243 int noshowwin;
1244 struct win *wi;
1246 ASSERT(display);
1247 pid = D_userpid;
1249 #ifdef REMOTE_DETACH
1250 if (m->m.attach.detachfirst == MSG_DETACH
1251 # ifdef POW_DETACH
1252 || m->m.attach.detachfirst == MSG_POW_DETACH
1253 # endif
1255 FinishDetach(m);
1256 #endif
1258 #if defined(pyr) || defined(xelos) || defined(sequent)
1260 * Kludge for systems with braindamaged termcap routines,
1261 * which evaluate $TERMCAP, regardless weather it describes
1262 * the correct terminal type or not.
1264 debug("unsetenv(TERMCAP) in case of a different terminal");
1265 unsetenv("TERMCAP");
1266 #endif
1269 * We reboot our Terminal Emulator. Forget all we knew about
1270 * the old terminal, reread the termcap entries in .screenrc
1271 * (and nothing more from .screenrc is read. Mainly because
1272 * I did not check, weather a full reinit is safe. jw)
1273 * and /etc/screenrc, and initialise anew.
1275 if (extra_outcap)
1276 free(extra_outcap);
1277 if (extra_incap)
1278 free(extra_incap);
1279 extra_incap = extra_outcap = 0;
1280 debug2("Message says size (%dx%d)\n", m->m.attach.columns, m->m.attach.lines);
1281 #ifdef ETCSCREENRC
1282 # ifdef ALLOW_SYSSCREENRC
1283 if ((p = getenv("SYSSCREENRC")))
1284 StartRc(p, 1);
1285 else
1286 # endif
1287 StartRc(ETCSCREENRC, 1);
1288 #endif
1289 StartRc(RcFileName, 1);
1290 if (InitTermcap(m->m.attach.columns, m->m.attach.lines))
1292 FreeDisplay();
1293 Kill(pid, SIG_BYE);
1294 return;
1296 MakeDefaultCanvas();
1297 InitTerm(m->m.attach.adaptflag); /* write init string on fd */
1298 if (displays->d_next == 0)
1299 (void) chsock();
1300 signal(SIGHUP, SigHup);
1301 if (m->m.attach.esc != -1 && m->m.attach.meta_esc != -1)
1303 D_user->u_Esc = m->m.attach.esc;
1304 D_user->u_MetaEsc = m->m.attach.meta_esc;
1307 #ifdef UTMPOK
1309 * we set the Utmp slots again, if we were detached normally
1310 * and if we were detached by ^Z.
1311 * don't log zomies back in!
1313 RemoveLoginSlot();
1314 if (displays->d_next == 0)
1315 for (wi = windows; wi; wi = wi->w_next)
1316 if (wi->w_ptyfd >= 0 && wi->w_slot != (slot_t) -1)
1317 SetUtmp(wi);
1318 #endif
1320 D_fore = NULL;
1321 if (layout_attach)
1323 struct layout *lay = layout_attach;
1324 if (lay == &layout_last_marker)
1325 lay = layout_last;
1326 if (lay)
1328 LoadLayout(lay, &D_canvas);
1329 SetCanvasWindow(D_forecv, 0);
1333 * there may be a window that we remember from last detach:
1335 debug1("D_user->u_detachwin = %d\n", D_user->u_detachwin);
1336 if (D_user->u_detachwin >= 0)
1337 fore = wtab[D_user->u_detachwin];
1338 else
1339 fore = 0;
1341 /* Wayne wants us to restore the other window too. */
1342 if (D_user->u_detachotherwin >= 0)
1343 D_other = wtab[D_user->u_detachotherwin];
1345 noshowwin = 0;
1346 if (*m->m.attach.preselect)
1348 if (!strcmp(m->m.attach.preselect, "="))
1349 fore = 0;
1350 else if (!strcmp(m->m.attach.preselect, "-"))
1352 fore = 0;
1353 noshowwin = 1;
1355 else if (!strcmp(m->m.attach.preselect, "+"))
1357 struct action newscreen;
1358 char *na = 0;
1359 newscreen.nr = RC_SCREEN;
1360 newscreen.args = &na;
1361 DoAction(&newscreen, -1);
1363 else
1364 fore = FindNiceWindow(fore, m->m.attach.preselect);
1366 else
1367 fore = FindNiceWindow(fore, 0);
1368 if (fore)
1369 SetForeWindow(fore);
1370 else if (!noshowwin)
1372 #ifdef MULTIUSER
1373 if (!AclCheckPermCmd(D_user, ACL_EXEC, &comms[RC_WINDOWLIST]))
1374 #endif
1376 flayer = D_forecv->c_layer;
1377 display_wlist(1, WLIST_NUM, (struct win *)0);
1378 noshowwin = 1;
1381 Activate(0);
1382 ResetIdle();
1383 if (!D_fore && !noshowwin)
1384 ShowWindows(-1);
1385 if (displays->d_next == 0 && console_window)
1387 if (TtyGrabConsole(console_window->w_ptyfd, 1, "reattach") == 0)
1388 Msg(0, "console %s is on window %d", HostName, console_window->w_number);
1390 debug("activated...\n");
1392 # if defined(DEBUG) && defined(SIG_NODEBUG)
1393 if (!dfp)
1395 sleep(1);
1396 debug1("Attacher %d must not debug, as we have debug off.\n", pid);
1397 kill(pid, SIG_NODEBUG);
1399 # endif /* SIG_NODEBUG */
1402 static void
1403 FinishDetach(m)
1404 struct msg *m;
1406 struct display *next, **d, *det;
1407 int pid;
1409 if (m->type == MSG_ATTACH)
1410 pid = D_userpid;
1411 else
1412 pid = m->m.detach.dpid;
1414 /* Remove the temporary display prompting for the password from the list */
1415 for (d = &displays; (det = *d); d = &det->d_next)
1417 if (det->d_userpid == pid)
1418 break;
1420 if (det)
1422 *d = det->d_next;
1423 det->d_next = 0;
1426 for (display = displays; display; display = next)
1428 next = display->d_next;
1429 # ifdef POW_DETACH
1430 if (m->type == MSG_POW_DETACH)
1431 Detach(D_REMOTE_POWER);
1432 else
1433 # endif /* POW_DETACH */
1434 if (m->type == MSG_DETACH)
1435 Detach(D_REMOTE);
1436 else if (m->type == MSG_ATTACH)
1438 #ifdef POW_DETACH
1439 if (m->m.attach.detachfirst == MSG_POW_DETACH)
1440 Detach(D_REMOTE_POWER);
1441 else
1442 #endif
1443 if (m->m.attach.detachfirst == MSG_DETACH)
1444 Detach(D_REMOTE);
1447 display = displays = det;
1448 if (m->type != MSG_ATTACH)
1450 if (display)
1451 FreeDisplay();
1452 Kill(pid, SIGCONT);
1456 #ifdef PASSWORD
1457 static void PasswordProcessInput __P((char *, int));
1459 struct pwdata {
1460 int l;
1461 char buf[20 + 1];
1462 struct msg m;
1465 static void
1466 AskPassword(m)
1467 struct msg *m;
1469 struct pwdata *pwdata;
1470 ASSERT(display);
1471 pwdata = (struct pwdata *)malloc(sizeof(struct pwdata));
1472 if (!pwdata)
1473 Panic(0, strnomem);
1474 pwdata->l = 0;
1475 pwdata->m = *m;
1476 D_processinputdata = (char *)pwdata;
1477 D_processinput = PasswordProcessInput;
1478 AddStr("Screen password: ");
1481 static void
1482 PasswordProcessInput(ibuf, ilen)
1483 char *ibuf;
1484 int ilen;
1486 struct pwdata *pwdata;
1487 int c, l;
1488 char *up;
1489 int pid = D_userpid;
1491 pwdata = (struct pwdata *)D_processinputdata;
1492 l = pwdata->l;
1493 while (ilen-- > 0)
1495 c = *(unsigned char *)ibuf++;
1496 if (c == '\r' || c == '\n')
1498 up = D_user->u_password;
1499 pwdata->buf[l] = 0;
1500 if (strncmp(crypt(pwdata->buf, up), up, strlen(up)))
1502 /* uh oh, user failed */
1503 bzero(pwdata->buf, sizeof(pwdata->buf));
1504 AddStr("\r\nPassword incorrect.\r\n");
1505 D_processinputdata = 0; /* otherwise freed by FreeDis */
1506 FreeDisplay();
1507 Msg(0, "Illegal reattach attempt from terminal %s.", pwdata->m.m_tty);
1508 free(pwdata);
1509 Kill(pid, SIG_BYE);
1510 return;
1512 /* great, pw matched, all is fine */
1513 bzero(pwdata->buf, sizeof(pwdata->buf));
1514 AddStr("\r\n");
1515 D_processinputdata = 0;
1516 D_processinput = ProcessInput;
1517 #ifdef REMOTE_DETACH
1518 if (pwdata->m.type == MSG_DETACH
1519 # ifdef POW_DETACH
1520 || pwdata->m.type == MSG_POW_DETACH
1521 # endif
1523 FinishDetach(&pwdata->m);
1524 else
1525 #endif
1526 FinishAttach(&pwdata->m);
1527 free(pwdata);
1528 return;
1530 if (c == Ctrl('c'))
1532 AddStr("\r\n");
1533 FreeDisplay();
1534 Kill(pid, SIG_BYE);
1535 return;
1537 if (c == '\b' || c == 0177)
1539 if (l > 0)
1540 l--;
1541 continue;
1543 if (c == Ctrl('u'))
1545 l = 0;
1546 continue;
1548 if (l < (int)sizeof(pwdata->buf) - 1)
1549 pwdata->buf[l++] = c;
1551 pwdata->l = l;
1553 #endif
1555 static void
1556 DoCommandMsg(mp)
1557 struct msg *mp;
1559 char *args[MAXARGS];
1560 int argl[MAXARGS];
1561 int n, *lp;
1562 register char **pp = args, *p = mp->m.command.cmd;
1563 struct acluser *user;
1564 #ifdef MULTIUSER
1565 extern struct acluser *EffectiveAclUser; /* acls.c */
1566 #else
1567 extern struct acluser *users; /* acls.c */
1568 #endif
1570 lp = argl;
1571 n = mp->m.command.nargs;
1572 if (n > MAXARGS - 1)
1573 n = MAXARGS - 1;
1574 for (; n > 0; n--)
1576 *pp++ = p;
1577 *lp = strlen(p);
1578 p += *lp++ + 1;
1580 *pp = 0;
1581 #ifdef MULTIUSER
1582 user = *FindUserPtr(mp->m.attach.auser);
1583 if (user == 0)
1585 Msg(0, "Unknown user %s tried to send a command!", mp->m.attach.auser);
1586 return;
1588 #else
1589 user = users;
1590 #endif
1591 #ifdef PASSWORD
1592 if (user->u_password && *user->u_password)
1594 Msg(0, "User %s has a password, cannot use -X option.", mp->m.attach.auser);
1595 return;
1597 #endif
1598 if (!display)
1599 for (display = displays; display; display = display->d_next)
1600 if (D_user == user)
1601 break;
1602 for (fore = windows; fore; fore = fore->w_next)
1603 if (!TTYCMP(mp->m_tty, fore->w_tty))
1605 if (!display)
1606 display = fore->w_layer.l_cvlist ? fore->w_layer.l_cvlist->c_display : 0;
1607 break;
1609 if (!display)
1610 display = displays; /* sigh */
1611 if (*mp->m.command.preselect)
1613 int i = -1;
1614 if (strcmp(mp->m.command.preselect, "-"))
1615 i = WindowByNoN(mp->m.command.preselect);
1616 fore = i >= 0 ? wtab[i] : 0;
1618 else if (!fore)
1620 if (display && D_user == user)
1621 fore = Layer2Window(display->d_forecv->c_layer);
1622 if (!fore)
1624 fore = user->u_detachwin >= 0 ? wtab[user->u_detachwin] : 0;
1625 fore = FindNiceWindow(fore, 0);
1628 if (!fore)
1629 fore = windows; /* sigh */
1630 #ifdef MULTIUSER
1631 EffectiveAclUser = user;
1632 #endif
1633 if (*args)
1635 char *oldrcname = rc_name;
1636 rc_name = "-X";
1637 debug3("Running command on display %x window %x (%d)\n", display, fore, fore ? fore->w_number : -1);
1638 flayer = fore ? &fore->w_layer : 0;
1639 if (fore && fore->w_savelayer && (fore->w_blocked || fore->w_savelayer->l_cvlist == 0))
1640 flayer = fore->w_savelayer;
1641 DoCommand(args, argl);
1642 rc_name = oldrcname;
1644 #ifdef MULTIUSER
1645 EffectiveAclUser = 0;
1646 #endif
1649 #ifndef NAMEDPIPE
1652 SendAttachMsg(s, m, fd)
1653 int s;
1654 struct msg *m;
1655 int fd;
1657 int r;
1658 struct msghdr msg;
1659 struct iovec iov;
1660 char buf[CMSG_SPACE(sizeof(int))];
1661 struct cmsghdr *cmsg;
1663 iov.iov_base = (char *)m;
1664 iov.iov_len = sizeof(*m);
1665 bzero(&msg, sizeof(msg));
1666 msg.msg_name = 0;
1667 msg.msg_namelen = 0;
1668 msg.msg_iov = &iov;
1669 msg.msg_iovlen = 1;
1670 msg.msg_control = buf;
1671 msg.msg_controllen = sizeof(buf);
1672 cmsg = CMSG_FIRSTHDR(&msg);
1673 cmsg->cmsg_level = SOL_SOCKET;
1674 cmsg->cmsg_type = SCM_RIGHTS;
1675 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
1676 bcopy(&fd, CMSG_DATA(cmsg), sizeof(int));
1677 msg.msg_controllen = cmsg->cmsg_len;
1678 while(1)
1680 r = sendmsg(s, &msg, 0);
1681 if (r == -1 && errno == EINTR)
1682 continue;
1683 if (r == -1)
1684 return -1;
1685 return 0;
1689 #endif