A display is not needed for remote window creation
[screen-lua.git] / src / socket.c
blob4c32ed57cdaf16800441186da56838501b84402b
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 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 struct sent
125 struct sent *next;
126 int mode;
127 char *name;
128 } *slist, **slisttail, *sent, *nsent;
130 if (match)
132 matchlen = strlen(match);
133 #ifdef NAME_MAX
134 if (matchlen > NAME_MAX)
135 matchlen = NAME_MAX;
136 #endif
140 * SockPath contains the socket directory.
141 * At the end of FindSocket the socket name will be appended to it.
142 * Thus FindSocket() can only be called once!
144 sdirlen = strlen(SockPath);
146 #ifdef USE_SETEUID
147 xseteuid(real_uid);
148 xsetegid(real_gid);
149 #endif
151 if ((dirp = opendir(SockPath)) == 0)
152 Panic(errno, "Cannot opendir %s", SockPath);
154 slist = 0;
155 slisttail = &slist;
156 while ((dp = readdir(dirp)))
158 name = dp->d_name;
159 debug1("- %s\n", name);
160 if (*name == 0 || *name == '.' || strlen(name) > 2*MAXSTR)
161 continue;
162 if (matchlen)
164 n = name;
165 /* if we don't want to match digits. Skip them */
166 if ((*match <= '0' || *match > '9') && (*n > '0' && *n <= '9'))
168 while (*n >= '0' && *n <= '9')
169 n++;
170 if (*n == '.')
171 n++;
173 /* the tty prefix is optional */
174 if (strncmp(match, "tty", 3) && strncmp(n, "tty", 3) == 0)
175 n += 3;
176 if (strncmp(match, n, matchlen))
177 continue;
178 debug1(" -> matched %s\n", match);
180 sprintf(SockPath + sdirlen, "/%s", name);
182 debug1("stat %s\n", SockPath);
183 errno = 0;
184 debug2("uid = %d, gid = %d\n", getuid(), getgid());
185 debug2("euid = %d, egid = %d\n", geteuid(), getegid());
186 if (stat(SockPath, &st))
188 debug1("errno = %d\n", errno);
189 continue;
192 #ifndef SOCK_NOT_IN_FS
193 # ifdef NAMEDPIPE
194 # ifdef S_ISFIFO
195 debug("S_ISFIFO?\n");
196 if (!S_ISFIFO(st.st_mode))
197 continue;
198 # endif
199 # else
200 # ifdef S_ISSOCK
201 debug("S_ISSOCK?\n");
202 if (!S_ISSOCK(st.st_mode))
203 continue;
204 # endif
205 # endif
206 #endif
208 debug2("st.st_uid = %d, real_uid = %d\n", st.st_uid, real_uid);
209 if ((int)st.st_uid != real_uid)
210 continue;
211 mode = (int)st.st_mode & 0777;
212 debug1(" has mode 0%03o\n", mode);
213 #ifdef MULTIUSER
214 if (multi && ((mode & 0677) != 0601))
216 debug(" is not a MULTI-USER session");
217 if (strcmp(multi, LoginName))
219 debug(" and we are in a foreign directory.\n");
220 mode = -4;
222 else
224 debug(", but it is our own session.\n");
227 #endif
228 debug(" store it.\n");
229 if ((sent = (struct sent *)malloc(sizeof(struct sent))) == 0)
230 continue;
231 sent->next = 0;
232 sent->name = SaveStr(name);
233 sent->mode = mode;
234 *slisttail = sent;
235 slisttail = &sent->next;
236 nfound++;
237 sockfd = MakeClientSocket(0);
238 #ifdef USE_SETEUID
239 /* MakeClientSocket sets ids back to eff */
240 xseteuid(real_uid);
241 xsetegid(real_gid);
242 #endif
243 if (sockfd == -1)
245 debug2(" MakeClientSocket failed, unreachable? %d %d\n",
246 matchlen, wipeflag);
247 sent->mode = -3;
248 #ifndef SOCKDIR_IS_LOCAL_TO_HOST
249 /* Unreachable - it is dead if we detect that it's local
250 * or we specified a match
252 n = name + strlen(name) - 1;
253 while (n != name && *n != '.')
254 n--;
255 if (matchlen == 0 && !(*n == '.' && n[1] && strncmp(HostName, n + 1, strlen(n + 1)) == 0))
257 npriv++; /* a good socket that was not for us */
258 continue;
260 #endif
261 ndead++;
262 sent->mode = -1;
263 if (wipeflag)
265 if (unlink(SockPath) == 0)
267 sent->mode = -2;
268 nwipe++;
271 continue;
274 mode &= 0776;
275 /* Shall we connect ? */
276 debug2(" connecting: mode=%03o, rflag=%d, ", mode, rflag);
277 debug2("xflag=%d, dflag=%d ?\n", xflag, dflag);
280 * mode 600: socket is detached.
281 * mode 700: socket is attached.
282 * xflag implies rflag here.
284 * fail, when socket mode mode is not 600 or 700
285 * fail, when we want to detach w/o reattach, but it already is detached.
286 * fail, when we only want to attach, but mode 700 and not xflag.
287 * fail, if none of dflag, rflag, xflag is set.
289 if ((mode != 0700 && mode != 0600) ||
290 (dflag && !rflag && !xflag && mode == 0600) ||
291 (!dflag && rflag && mode == 0700 && !xflag) ||
292 (!dflag && !rflag && !xflag))
294 close(sockfd);
295 debug(" no!\n");
296 npriv++; /* a good socket that was not for us */
297 continue;
299 ngood++;
300 if (fdp && firsts == -1)
302 firsts = sockfd;
303 firstn = sent->name;
304 debug(" taken.\n");
306 else
308 debug(" discarded.\n");
309 close(sockfd);
312 (void)closedir(dirp);
313 if (nfound && (lsflag || ngood != 1) && !quietflag)
315 switch(ngood)
317 case 0:
318 Msg(0, nfound > 1 ? "There are screens on:" : "There is a screen on:");
319 break;
320 case 1:
321 Msg(0, nfound > 1 ? "There are several screens on:" : "There is a suitable screen on:");
322 break;
323 default:
324 Msg(0, "There are several suitable screens on:");
325 break;
327 for (sent = slist; sent; sent = sent->next)
329 switch (sent->mode)
331 case 0700:
332 printf("\t%s\t(Attached)\n", sent->name);
333 break;
334 case 0600:
335 printf("\t%s\t(Detached)\n", sent->name);
336 break;
337 #ifdef MULTIUSER
338 case 0701:
339 printf("\t%s\t(Multi, attached)\n", sent->name);
340 break;
341 case 0601:
342 printf("\t%s\t(Multi, detached)\n", sent->name);
343 break;
344 #endif
345 case -1:
346 /* No trigraphs here! */
347 printf("\t%s\t(Dead ?%c?)\n", sent->name, '?');
348 break;
349 case -2:
350 printf("\t%s\t(Removed)\n", sent->name);
351 break;
352 case -3:
353 printf("\t%s\t(Remote or dead)\n", sent->name);
354 break;
355 case -4:
356 printf("\t%s\t(Private)\n", sent->name);
357 break;
361 if (ndead && !quietflag)
363 char *m = "Remove dead screens with 'screen -wipe'.";
364 if (wipeflag)
365 Msg(0, "%d socket%s wiped out.", nwipe, nwipe > 1 ? "s" : "");
366 else
367 Msg(0, m, ndead > 1 ? "s" : "", ndead > 1 ? "" : "es"); /* other args for nethack */
369 if (firsts != -1)
371 sprintf(SockPath + sdirlen, "/%s", firstn);
372 *fdp = firsts;
374 else
375 SockPath[sdirlen] = 0;
376 for (sent = slist; sent; sent = nsent)
378 nsent = sent->next;
379 free(sent->name);
380 free((char *)sent);
382 #ifdef USE_SETEUID
383 xseteuid(eff_uid);
384 xsetegid(eff_gid);
385 #endif
386 if (notherp)
387 *notherp = npriv;
388 if (nfoundp)
389 *nfoundp = nfound - nwipe;
390 return ngood;
396 ** Socket/pipe create routines
400 #ifdef NAMEDPIPE
403 MakeServerSocket()
405 register int s;
406 struct stat st;
408 # ifdef USE_SETEUID
409 xseteuid(real_uid);
410 xsetegid(real_gid);
411 # endif
412 if ((s = open(SockPath, O_WRONLY | O_NONBLOCK)) >= 0)
414 debug("huii, my fifo already exists??\n");
415 if (quietflag)
417 Kill(D_userpid, SIG_BYE);
418 eexit(11);
420 Msg(0, "There is already a screen running on %s.", Filename(SockPath));
421 if (stat(SockPath, &st) == -1)
422 Panic(errno, "stat");
423 if ((int)st.st_uid != real_uid)
424 Panic(0, "Unfortunatelly you are not its owner.");
425 if ((st.st_mode & 0700) == 0600)
426 Panic(0, "To resume it, use \"screen -r\"");
427 else
428 Panic(0, "It is not detached.");
429 /* NOTREACHED */
431 # ifdef USE_SETEUID
432 (void) unlink(SockPath);
433 if (mkfifo(SockPath, SOCKMODE))
434 Panic(0, "mkfifo %s failed", SockPath);
435 # ifdef BROKEN_PIPE
436 if ((s = open(SockPath, O_RDWR | O_NONBLOCK, 0)) < 0)
437 # else
438 if ((s = open(SockPath, O_RDONLY | O_NONBLOCK, 0)) < 0)
439 # endif
440 Panic(errno, "open fifo %s", SockPath);
441 xseteuid(eff_uid);
442 xsetegid(eff_gid);
443 return s;
444 # else /* !USE_SETEUID */
445 if (UserContext() > 0)
447 (void) unlink(SockPath);
448 UserReturn(mkfifo(SockPath, SOCKMODE));
450 if (UserStatus())
451 Panic(0, "mkfifo %s failed", SockPath);
452 # ifdef BROKEN_PIPE
453 if ((s = secopen(SockPath, O_RDWR | O_NONBLOCK, 0)) < 0)
454 # else
455 if ((s = secopen(SockPath, O_RDONLY | O_NONBLOCK, 0)) < 0)
456 # endif
457 Panic(errno, "open fifo %s", SockPath);
458 return s;
459 # endif /* !USE_SETEUID */
464 MakeClientSocket(err)
465 int err;
467 register int s = 0;
469 if ((s = secopen(SockPath, O_WRONLY | O_NONBLOCK, 0)) >= 0)
471 (void) fcntl(s, F_SETFL, 0);
472 return s;
474 if (err)
475 Msg(errno, "%s", SockPath);
476 debug2("MakeClientSocket() open %s failed (%d)\n", SockPath, errno);
477 return -1;
481 #else /* NAMEDPIPE */
485 MakeServerSocket()
487 register int s;
488 struct sockaddr_un a;
489 struct stat st;
491 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
492 Panic(errno, "socket");
493 a.sun_family = AF_UNIX;
494 strncpy(a.sun_path, SockPath, sizeof(a.sun_path));
495 a.sun_path[sizeof(a.sun_path) - 1] = 0;
496 # ifdef USE_SETEUID
497 xseteuid(real_uid);
498 xsetegid(real_gid);
499 # endif
500 if (connect(s, (struct sockaddr *) &a, strlen(SockPath) + 2) != -1)
502 debug("oooooh! socket already is alive!\n");
503 if (quietflag)
505 Kill(D_userpid, SIG_BYE);
507 * oh, well. nobody receives that return code. papa
508 * dies by signal.
510 eexit(11);
512 Msg(0, "There is already a screen running on %s.", Filename(SockPath));
513 if (stat(SockPath, &st) == -1)
514 Panic(errno, "stat");
515 if (st.st_uid != real_uid)
516 Panic(0, "Unfortunatelly you are not its owner.");
517 if ((st.st_mode & 0700) == 0600)
518 Panic(0, "To resume it, use \"screen -r\"");
519 else
520 Panic(0, "It is not detached.");
521 /* NOTREACHED */
523 #if defined(m88k) || defined(sysV68)
524 close(s); /* we get bind: Invalid argument if this is not done */
525 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
526 Panic(errno, "reopen socket");
527 #endif
528 (void) unlink(SockPath);
529 if (bind(s, (struct sockaddr *) & a, strlen(SockPath) + 2) == -1)
530 Panic(errno, "bind (%s)", SockPath);
531 #ifdef SOCK_NOT_IN_FS
533 int f;
534 if ((f = secopen(SockPath, O_RDWR | O_CREAT, SOCKMODE)) < 0)
535 Panic(errno, "shadow socket open");
536 close(f);
538 #else
539 chmod(SockPath, SOCKMODE);
540 # ifndef USE_SETEUID
541 chown(SockPath, real_uid, real_gid);
542 # endif
543 #endif /* SOCK_NOT_IN_FS */
544 if (listen(s, 5) == -1)
545 Panic(errno, "listen");
546 # ifdef F_SETOWN
547 fcntl(s, F_SETOWN, getpid());
548 debug1("Serversocket owned by %d\n", fcntl(s, F_GETOWN, 0));
549 # endif /* F_SETOWN */
550 # ifdef USE_SETEUID
551 xseteuid(eff_uid);
552 xsetegid(eff_gid);
553 # endif
554 return s;
558 MakeClientSocket(err)
559 int err;
561 register int s;
562 struct sockaddr_un a;
564 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
565 Panic(errno, "socket");
566 a.sun_family = AF_UNIX;
567 strncpy(a.sun_path, SockPath, sizeof(a.sun_path));
568 a.sun_path[sizeof(a.sun_path) - 1] = 0;
569 # ifdef USE_SETEUID
570 xseteuid(real_uid);
571 xsetegid(real_gid);
572 # else
573 if (access(SockPath, W_OK))
575 if (err)
576 Msg(errno, "%s", SockPath);
577 debug2("MakeClientSocket: access(%s): %d.\n", SockPath, errno);
578 close(s);
579 return -1;
581 # endif
582 if (connect(s, (struct sockaddr *) &a, strlen(SockPath) + 2) == -1)
584 if (err)
585 Msg(errno, "%s: connect", SockPath);
586 debug("MakeClientSocket: connect failed.\n");
587 close(s);
588 s = -1;
590 # ifdef USE_SETEUID
591 xseteuid(eff_uid);
592 xsetegid(eff_gid);
593 # endif
594 return s;
596 #endif /* NAMEDPIPE */
601 ** Message send and receive routines
605 void
606 SendCreateMsg(sty, nwin)
607 char *sty;
608 struct NewWindow *nwin;
610 int s;
611 struct msg m;
612 register char *p;
613 register int len, n;
614 char **av = nwin->args;
616 #ifdef NAME_MAX
617 if (strlen(sty) > NAME_MAX)
618 sty[NAME_MAX] = 0;
619 #endif
620 if (strlen(sty) > 2 * MAXSTR - 1)
621 sty[2 * MAXSTR - 1] = 0;
622 sprintf(SockPath + strlen(SockPath), "/%s", sty);
623 if ((s = MakeClientSocket(1)) == -1)
624 exit(1);
625 debug1("SendCreateMsg() to '%s'\n", SockPath);
626 bzero((char *)&m, sizeof(m));
627 m.type = MSG_CREATE;
628 strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1);
629 m.m_tty[sizeof(m.m_tty) - 1] = 0;
630 p = m.m.create.line;
631 n = 0;
632 if (nwin->args != nwin_undef.args)
633 for (av = nwin->args; *av && n < MAXARGS - 1; ++av, ++n)
635 len = strlen(*av) + 1;
636 if (p + len >= m.m.create.line + sizeof(m.m.create.line) - 1)
637 break;
638 strcpy(p, *av);
639 p += len;
641 if (nwin->aka != nwin_undef.aka && p + strlen(nwin->aka) + 1 < m.m.create.line + sizeof(m.m.create.line))
642 strcpy(p, nwin->aka);
643 else
644 *p = '\0';
645 m.m.create.nargs = n;
646 m.m.create.aflag = nwin->aflag;
647 m.m.create.flowflag = nwin->flowflag;
648 m.m.create.lflag = nwin->lflag;
649 m.m.create.hheight = nwin->histheight;
650 if (getcwd(m.m.create.dir, sizeof(m.m.create.dir)) == 0)
652 Msg(errno, "getcwd");
653 return;
655 if (nwin->term != nwin_undef.term)
656 strncpy(m.m.create.screenterm, nwin->term, 19);
657 m.m.create.screenterm[19] = '\0';
658 m.protocol_revision = MSG_REVISION;
659 debug1("SendCreateMsg writing '%s'\n", m.m.create.line);
660 if (write(s, (char *) &m, sizeof m) != sizeof m)
661 Msg(errno, "write");
662 close(s);
666 SendErrorMsg(tty, buf)
667 char *tty, *buf;
669 int s;
670 struct msg m;
672 strncpy(m.m.message, buf, sizeof(m.m.message) - 1);
673 m.m.message[sizeof(m.m.message) - 1] = 0;
674 s = MakeClientSocket(0);
675 if (s < 0)
676 return -1;
677 m.type = MSG_ERROR;
678 strncpy(m.m_tty, tty, sizeof(m.m_tty) - 1);
679 m.m_tty[sizeof(m.m_tty) - 1] = 0;
680 m.protocol_revision = MSG_REVISION;
681 debug1("SendErrorMsg(): writing to '%s'\n", SockPath);
682 (void) write(s, (char *) &m, sizeof m);
683 close(s);
684 return 0;
687 static void
688 ExecCreate(mp)
689 struct msg *mp;
691 struct NewWindow nwin;
692 char *args[MAXARGS];
693 register int n;
694 register char **pp = args, *p = mp->m.create.line;
696 nwin = nwin_undef;
697 n = mp->m.create.nargs;
698 if (n > MAXARGS - 1)
699 n = MAXARGS - 1;
700 /* ugly hack alert... should be done by the frontend! */
701 if (n)
703 int l, num;
704 char buf[20];
706 l = strlen(p);
707 if (IsNumColon(p, 10, buf, sizeof(buf)))
709 if (*buf)
710 nwin.aka = buf;
711 num = atoi(p);
712 if (num < 0 || num > MAXWIN - 1)
713 num = 0;
714 nwin.StartAt = num;
715 p += l + 1;
716 n--;
719 for (; n > 0; n--)
721 *pp++ = p;
722 p += strlen(p) + 1;
724 *pp = 0;
725 if (*p)
726 nwin.aka = p;
727 if (*args)
728 nwin.args = args;
729 nwin.aflag = mp->m.create.aflag;
730 nwin.flowflag = mp->m.create.flowflag;
731 if (*mp->m.create.dir)
732 nwin.dir = mp->m.create.dir;
733 nwin.lflag = mp->m.create.lflag;
734 nwin.histheight = mp->m.create.hheight;
735 if (*mp->m.create.screenterm)
736 nwin.term = mp->m.create.screenterm;
737 MakeWindow(&nwin);
740 static int
741 CheckPid(pid)
742 int pid;
744 debug1("Checking pid %d\n", pid);
745 if (pid < 2)
746 return -1;
747 if (eff_uid == real_uid)
748 return kill(pid, 0);
749 if (UserContext() > 0)
750 UserReturn(kill(pid, 0));
751 return UserStatus();
754 #ifdef hpux
756 * From: "F. K. Bruner" <napalm@ugcs.caltech.edu>
757 * From: "Dan Egnor" <egnor@oracorp.com> Tue Aug 10 06:56:45 1993
758 * The problem is that under HPUX (and possibly other systems too) there are
759 * two equivalent device files for each pty/tty device:
760 * /dev/ttyxx == /dev/pty/ttyxx
761 * /dev/ptyxx == /dev/ptym/ptyxx
762 * I didn't look into the exact specifics, but I've run across this problem
763 * before: Even if you open /dev/ttyxx as fds 0 1 & 2 for a process, if that
764 * process calls the system to determine its tty, it'll get /dev/pty/ttyxx.
766 * Earlier versions seemed to work -- wonder what they did.
768 static int
769 ttycmp(s1, s2)
770 char *s1, *s2;
772 if (strlen(s1) > 5) s1 += strlen(s1) - 5;
773 if (strlen(s2) > 5) s2 += strlen(s2) - 5;
774 return strcmp(s1, s2);
776 # define TTYCMP(a, b) ttycmp(a, b)
777 #else
778 # define TTYCMP(a, b) strcmp(a, b)
779 #endif
781 static int
782 CreateTempDisplay(m, recvfd, wi)
783 struct msg *m;
784 int recvfd;
785 struct win *wi;
787 int pid;
788 int attach;
789 char *user;
790 int i;
791 struct mode Mode;
792 struct display *olddisplays = displays;
794 switch (m->type)
796 case MSG_ATTACH:
797 pid = m->m.attach.apid;
798 user = m->m.attach.auser;
799 attach = 1;
800 break;
801 #ifdef REMOTE_DETACH
802 case MSG_DETACH:
803 # ifdef POW_DETACH
804 case MSG_POW_DETACH:
805 # endif /* POW_DETACH */
806 pid = m->m.detach.dpid;
807 user = m->m.detach.duser;
808 attach = 0;
809 break;
810 #endif
811 default:
812 return -1;
815 if (CheckPid(pid))
817 Msg(0, "Attach attempt with bad pid(%d)!", pid);
818 return -1;
820 if (recvfd != -1)
822 char *myttyname;
823 i = recvfd;
824 recvfd = -1;
825 myttyname = ttyname(i);
826 if (myttyname == 0 || strcmp(myttyname, m->m_tty))
828 Msg(errno, "Attach: passed fd does not match tty: %s - %s!", m->m_tty, myttyname ? myttyname : "NULL");
829 close(i);
830 Kill(pid, SIG_BYE);
831 return -1;
834 else if ((i = secopen(m->m_tty, O_RDWR | O_NONBLOCK, 0)) < 0)
836 Msg(errno, "Attach: Could not open %s!", m->m_tty);
837 Kill(pid, SIG_BYE);
838 return -1;
840 #ifdef MULTIUSER
841 if (attach)
842 Kill(pid, SIGCONT);
843 #endif
845 #if defined(ultrix) || defined(pyr) || defined(NeXT)
846 brktty(i); /* for some strange reason this must be done */
847 #endif
849 if (attach)
851 if (display || wi)
853 write(i, "Attaching from inside of screen?\n", 33);
854 close(i);
855 Kill(pid, SIG_BYE);
856 Msg(0, "Attach msg ignored: coming from inside.");
857 return -1;
860 #ifdef MULTIUSER
861 if (strcmp(user, LoginName))
862 if (*FindUserPtr(user) == 0)
864 write(i, "Access to session denied.\n", 26);
865 close(i);
866 Kill(pid, SIG_BYE);
867 Msg(0, "Attach: access denied for user %s.", user);
868 return -1;
870 #endif
872 debug2("RecMsg: apid %d is o.k. and we just opened '%s'\n", pid, m->m_tty);
873 #ifndef MULTI
874 if (displays)
876 write(i, "Screen session in use.\n", 23);
877 close(i);
878 Kill(pid, SIG_BYE);
879 return -1;
881 #endif
884 /* create new display */
885 GetTTY(i, &Mode);
886 if (MakeDisplay(user, m->m_tty, attach ? m->m.attach.envterm : "", i, pid, &Mode) == 0)
888 write(i, "Could not make display.\n", 24);
889 close(i);
890 Msg(0, "Attach: could not make display for user %s", user);
891 Kill(pid, SIG_BYE);
892 return -1;
894 #ifdef ENCODINGS
895 if (attach)
897 # ifdef UTF8
898 D_encoding = m->m.attach.encoding == 1 ? UTF8 : m->m.attach.encoding ? m->m.attach.encoding - 1 : 0;
899 # else
900 D_encoding = m->m.attach.encoding ? m->m.attach.encoding - 1 : 0;
901 # endif
902 if (D_encoding < 0 || !EncodingName(D_encoding))
903 D_encoding = 0;
904 #endif
907 if (iflag && olddisplays)
909 iflag = 0;
910 #if defined(TERMIO) || defined(POSIX)
911 olddisplays->d_NewMode.tio.c_cc[VINTR] = VDISABLE;
912 olddisplays->d_NewMode.tio.c_lflag &= ~ISIG;
913 #else /* TERMIO || POSIX */
914 olddisplays->d_NewMode.m_tchars.t_intrc = -1;
915 #endif /* TERMIO || POSIX */
916 SetTTY(olddisplays->d_userfd, &olddisplays->d_NewMode);
918 SetMode(&D_OldMode, &D_NewMode, D_flow, iflag);
919 SetTTY(D_userfd, &D_NewMode);
920 if (fcntl(D_userfd, F_SETFL, FNBLOCK))
921 Msg(errno, "Warning: NBLOCK fcntl failed");
922 return 0;
925 void
926 ReceiveMsg()
928 int left, len;
929 static struct msg m;
930 char *p;
931 int ns = ServerSocket;
932 struct win *wi;
933 int recvfd = -1;
934 struct acluser *user;
936 #ifdef NAMEDPIPE
937 debug("Ha, there was someone knocking on my fifo??\n");
938 if (fcntl(ServerSocket, F_SETFL, 0) == -1)
939 Panic(errno, "BLOCK fcntl");
940 p = (char *) &m;
941 left = sizeof(m);
942 #else
943 struct sockaddr_un a;
944 struct msghdr msg;
945 struct iovec iov;
946 char control[1024];
948 len = sizeof(a);
949 debug("Ha, there was someone knocking on my socket??\n");
950 if ((ns = accept(ns, (struct sockaddr *) &a, (void *)&len)) < 0)
952 Msg(errno, "accept");
953 return;
956 p = (char *) &m;
957 left = sizeof(m);
958 bzero(&msg, sizeof(msg));
959 iov.iov_base = &m;
960 iov.iov_len = left;
961 msg.msg_iov = &iov;
962 msg.msg_iovlen = 1;
963 msg.msg_controllen = sizeof(control);
964 msg.msg_control = &control;
965 while (left > 0)
967 len = recvmsg(ns, &msg, 0);
968 if (len < 0 && errno == EINTR)
969 continue;
970 if (len < 0)
972 close(ns);
973 Msg(errno, "read");
974 return;
976 if (msg.msg_controllen)
978 struct cmsghdr *cmsg;
979 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
981 int cl;
982 char *cp;
983 if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS)
984 continue;
985 cp = (char *)CMSG_DATA(cmsg);
986 cl = cmsg->cmsg_len;
987 while(cl >= CMSG_LEN(sizeof(int)))
989 int passedfd;
990 bcopy(cp, &passedfd, sizeof(int));
991 if (recvfd >= 0 && passedfd != recvfd)
992 close(recvfd);
993 recvfd = passedfd;
994 cl -= CMSG_LEN(sizeof(int));
998 p += len;
999 left -= len;
1000 break;
1003 #endif
1005 while (left > 0)
1007 len = read(ns, p, left);
1008 if (len < 0 && errno == EINTR)
1009 continue;
1010 if (len <= 0)
1011 break;
1012 p += len;
1013 left -= len;
1016 #ifdef NAMEDPIPE
1017 # ifndef BROKEN_PIPE
1018 /* Reopen pipe to prevent EOFs at the select() call */
1019 close(ServerSocket);
1020 if ((ServerSocket = secopen(SockPath, O_RDONLY | O_NONBLOCK, 0)) < 0)
1021 Panic(errno, "reopen fifo %s", SockPath);
1022 evdeq(&serv_read);
1023 serv_read.fd = ServerSocket;
1024 evenq(&serv_read);
1025 # endif
1026 #else
1027 close(ns);
1028 #endif
1030 if (len < 0)
1032 Msg(errno, "read");
1033 if (recvfd != -1)
1034 close(recvfd);
1035 return;
1037 if (left > 0)
1039 if (left != sizeof(m))
1040 Msg(0, "Message %d of %d bytes too small", left, (int)sizeof(m));
1041 else
1042 debug("No data on socket.\n");
1043 return;
1045 if (m.protocol_revision != MSG_REVISION)
1047 if (recvfd != -1)
1048 close(recvfd);
1049 Msg(0, "Invalid message (magic 0x%08x).", m.protocol_revision);
1050 return;
1053 debug2("*** RecMsg: type %d tty %s\n", m.type, m.m_tty);
1054 if (m.type != MSG_ATTACH && recvfd != -1)
1056 close(recvfd);
1057 recvfd = -1;
1060 for (display = displays; display; display = display->d_next)
1061 if (TTYCMP(D_usertty, m.m_tty) == 0)
1062 break;
1063 debug2("display: %s display %sfound\n", m.m_tty, display ? "" : "not ");
1064 wi = 0;
1065 if (!display)
1067 for (wi = windows; wi; wi = wi->w_next)
1068 if (!TTYCMP(m.m_tty, wi->w_tty))
1070 /* XXX: hmmm, rework this? */
1071 display = wi->w_layer.l_cvlist ? wi->w_layer.l_cvlist->c_display : 0;
1072 debug2("but window %s %sfound.\n", m.m_tty, display ? "" :
1073 "(backfacing)");
1074 break;
1078 /* Remove the status to prevent garbage on the screen */
1079 if (display && D_status)
1080 RemoveStatus();
1082 if (display && !D_tcinited && m.type != MSG_HANGUP)
1084 if (recvfd != -1)
1085 close(recvfd);
1086 return; /* ignore messages for bad displays */
1089 switch (m.type)
1091 case MSG_WINCH:
1092 if (display)
1093 CheckScreenSize(1); /* Change fore */
1094 break;
1095 case MSG_CREATE:
1097 * the window that issued the create message need not be an active
1098 * window. Then we create the window without having a display.
1099 * Resulting in another inactive window.
1101 ExecCreate(&m);
1102 break;
1103 case MSG_CONT:
1104 if (display && D_userpid != 0 && kill(D_userpid, 0) == 0)
1105 break; /* Intruder Alert */
1106 debug2("RecMsg: apid=%d,was %d\n", m.m.attach.apid, display ? D_userpid : 0);
1107 /* FALLTHROUGH */
1109 case MSG_ATTACH:
1110 if (CreateTempDisplay(&m, recvfd, wi))
1111 break;
1112 #ifdef PASSWORD
1113 if (D_user->u_password && *D_user->u_password)
1114 AskPassword(&m);
1115 else
1116 #endif
1117 FinishAttach(&m);
1118 break;
1119 case MSG_ERROR:
1120 Msg(0, "%s", m.m.message);
1121 break;
1122 case MSG_HANGUP:
1123 if (!wi) /* ignore hangups from inside */
1124 Hangup();
1125 break;
1126 #ifdef REMOTE_DETACH
1127 case MSG_DETACH:
1128 # ifdef POW_DETACH
1129 case MSG_POW_DETACH:
1130 # endif /* POW_DETACH */
1131 #ifdef PASSWORD
1132 user = *FindUserPtr(m.m.detach.duser);
1133 if (user && user->u_password && *user->u_password)
1135 if (CreateTempDisplay(&m, recvfd, 0))
1136 break;
1137 AskPassword(&m);
1139 else
1140 #endif /* PASSWORD */
1141 FinishDetach(&m);
1142 break;
1143 #endif
1144 case MSG_COMMAND:
1145 DoCommandMsg(&m);
1146 break;
1147 default:
1148 Msg(0, "Invalid message (type %d).", m.type);
1152 #if defined(_SEQUENT_) && !defined(NAMEDPIPE)
1153 #undef connect
1155 * sequent_ptx socket emulation must have mode 000 on the socket!
1157 static int
1158 sconnect(s, sapp, len)
1159 int s, len;
1160 struct sockaddr *sapp;
1162 register struct sockaddr_un *sap;
1163 struct stat st;
1164 int x;
1166 sap = (struct sockaddr_un *)sapp;
1167 if (stat(sap->sun_path, &st))
1168 return -1;
1169 chmod(sap->sun_path, 0);
1170 x = connect(s, (struct sockaddr *) sap, len);
1171 chmod(sap->sun_path, st.st_mode);
1172 return x;
1174 #endif
1178 * Set the mode bits of the socket to the current status
1181 chsock()
1183 int r, euid = geteuid();
1184 if (euid != real_uid)
1186 if (UserContext() <= 0)
1187 return UserStatus();
1189 r = chmod(SockPath, SOCKMODE);
1191 * Sockets usually reside in the /tmp/ area, where sysadmin scripts
1192 * may be happy to remove old files. We manually prevent the socket
1193 * from becoming old. (chmod does not touch mtime).
1195 (void)utimes(SockPath, NULL);
1197 if (euid != real_uid)
1198 UserReturn(r);
1199 return r;
1203 * Try to recreate the socket/pipe
1206 RecoverSocket()
1208 close(ServerSocket);
1209 if ((int)geteuid() != real_uid)
1211 if (UserContext() > 0)
1212 UserReturn(unlink(SockPath));
1213 (void)UserStatus();
1215 else
1216 (void) unlink(SockPath);
1218 if ((ServerSocket = MakeServerSocket()) < 0)
1219 return 0;
1220 evdeq(&serv_read);
1221 serv_read.fd = ServerSocket;
1222 evenq(&serv_read);
1223 return 1;
1227 static void
1228 FinishAttach(m)
1229 struct msg *m;
1231 char *p;
1232 int pid;
1233 int noshowwin;
1234 struct win *wi;
1236 ASSERT(display);
1237 pid = D_userpid;
1239 if (m->m.attach.detachfirst != MSG_ATTACH)
1240 FinishDetach(m);
1242 #if defined(pyr) || defined(xelos) || defined(sequent)
1244 * Kludge for systems with braindamaged termcap routines,
1245 * which evaluate $TERMCAP, regardless weather it describes
1246 * the correct terminal type or not.
1248 debug("unsetenv(TERMCAP) in case of a different terminal");
1249 unsetenv("TERMCAP");
1250 #endif
1253 * We reboot our Terminal Emulator. Forget all we knew about
1254 * the old terminal, reread the termcap entries in .screenrc
1255 * (and nothing more from .screenrc is read. Mainly because
1256 * I did not check, weather a full reinit is safe. jw)
1257 * and /etc/screenrc, and initialise anew.
1259 if (extra_outcap)
1260 free(extra_outcap);
1261 if (extra_incap)
1262 free(extra_incap);
1263 extra_incap = extra_outcap = 0;
1264 debug2("Message says size (%dx%d)\n", m->m.attach.columns, m->m.attach.lines);
1265 #ifdef ETCSCREENRC
1266 # ifdef ALLOW_SYSSCREENRC
1267 if ((p = getenv("SYSSCREENRC")))
1268 StartRc(p, 1);
1269 else
1270 # endif
1271 StartRc(ETCSCREENRC, 1);
1272 #endif
1273 StartRc(RcFileName, 1);
1274 if (InitTermcap(m->m.attach.columns, m->m.attach.lines))
1276 FreeDisplay();
1277 Kill(pid, SIG_BYE);
1278 return;
1280 MakeDefaultCanvas();
1281 InitTerm(m->m.attach.adaptflag); /* write init string on fd */
1282 if (displays->d_next == 0)
1283 (void) chsock();
1284 signal(SIGHUP, SigHup);
1285 if (m->m.attach.esc != -1 && m->m.attach.meta_esc != -1)
1287 D_user->u_Esc = m->m.attach.esc;
1288 D_user->u_MetaEsc = m->m.attach.meta_esc;
1291 #ifdef UTMPOK
1293 * we set the Utmp slots again, if we were detached normally
1294 * and if we were detached by ^Z.
1295 * don't log zomies back in!
1297 RemoveLoginSlot();
1298 if (displays->d_next == 0)
1299 for (wi = windows; wi; wi = wi->w_next)
1300 if (wi->w_ptyfd >= 0 && wi->w_slot != (slot_t) -1)
1301 SetUtmp(wi);
1302 #endif
1304 D_fore = NULL;
1305 if (layout_attach)
1307 struct layout *lay = layout_attach;
1308 if (lay == &layout_last_marker)
1309 lay = layout_last;
1310 if (lay)
1312 LoadLayout(lay, &D_canvas);
1313 SetCanvasWindow(D_forecv, 0);
1317 * there may be a window that we remember from last detach:
1319 debug1("D_user->u_detachwin = %d\n", D_user->u_detachwin);
1320 if (D_user->u_detachwin >= 0)
1321 fore = wtab[D_user->u_detachwin];
1322 else
1323 fore = 0;
1325 /* Wayne wants us to restore the other window too. */
1326 if (D_user->u_detachotherwin >= 0)
1327 D_other = wtab[D_user->u_detachotherwin];
1329 noshowwin = 0;
1330 if (*m->m.attach.preselect)
1332 if (!strcmp(m->m.attach.preselect, "="))
1333 fore = 0;
1334 else if (!strcmp(m->m.attach.preselect, "-"))
1336 fore = 0;
1337 noshowwin = 1;
1339 else if (!strcmp(m->m.attach.preselect, "+"))
1341 struct action newscreen;
1342 char *na = 0;
1343 newscreen.nr = RC_SCREEN;
1344 newscreen.args = &na;
1345 DoAction(&newscreen, -1);
1347 else
1348 fore = FindNiceWindow(fore, m->m.attach.preselect);
1350 else
1351 fore = FindNiceWindow(fore, 0);
1352 if (fore)
1353 SetForeWindow(fore);
1354 else if (!noshowwin)
1356 #ifdef MULTIUSER
1357 if (!AclCheckPermCmd(D_user, ACL_EXEC, &comms[RC_WINDOWLIST]))
1358 #endif
1360 flayer = D_forecv->c_layer;
1361 display_wlist(1, WLIST_NUM, (struct win *)0);
1362 noshowwin = 1;
1365 Activate(0);
1366 ResetIdle();
1367 if (!D_fore && !noshowwin)
1368 ShowWindows(-1);
1369 if (displays->d_next == 0 && console_window)
1371 if (TtyGrabConsole(console_window->w_ptyfd, 1, "reattach") == 0)
1372 Msg(0, "console %s is on window %d", HostName, console_window->w_number);
1374 debug("activated...\n");
1376 # if defined(DEBUG) && defined(SIG_NODEBUG)
1377 if (!dfp)
1379 sleep(1);
1380 debug1("Attacher %d must not debug, as we have debug off.\n", pid);
1381 kill(pid, SIG_NODEBUG);
1383 # endif /* SIG_NODEBUG */
1386 static void
1387 FinishDetach(m)
1388 struct msg *m;
1390 struct display *next, **d, *det;
1391 int pid;
1393 if (m->type == MSG_ATTACH)
1394 pid = D_userpid;
1395 else
1396 pid = m->m.detach.dpid;
1398 /* Remove the temporary display prompting for the password from the list */
1399 for (d = &displays; (det = *d); d = &det->d_next)
1401 if (det->d_userpid == pid)
1402 break;
1404 if (det)
1406 *d = det->d_next;
1407 det->d_next = 0;
1410 for (display = displays; display; display = next)
1412 next = display->d_next;
1413 # ifdef POW_DETACH
1414 if (m->type == MSG_POW_DETACH)
1415 Detach(D_REMOTE_POWER);
1416 else
1417 # endif /* POW_DETACH */
1418 if (m->type == MSG_DETACH)
1419 Detach(D_REMOTE);
1420 else if (m->type == MSG_ATTACH)
1422 #ifdef POW_DETACH
1423 if (m->m.attach.detachfirst == MSG_POW_DETACH)
1424 Detach(D_REMOTE_POWER);
1425 else
1426 #endif
1427 if (m->m.attach.detachfirst == MSG_DETACH)
1428 Detach(D_REMOTE);
1431 display = displays = det;
1432 if (m->type != MSG_ATTACH)
1434 if (display)
1435 FreeDisplay();
1436 Kill(pid, SIGCONT);
1440 #ifdef PASSWORD
1441 static void PasswordProcessInput __P((char *, int));
1443 struct pwdata {
1444 int l;
1445 char buf[20 + 1];
1446 struct msg m;
1449 static void
1450 AskPassword(m)
1451 struct msg *m;
1453 struct pwdata *pwdata;
1454 ASSERT(display);
1455 pwdata = (struct pwdata *)malloc(sizeof(struct pwdata));
1456 if (!pwdata)
1457 Panic(0, strnomem);
1458 pwdata->l = 0;
1459 pwdata->m = *m;
1460 D_processinputdata = (char *)pwdata;
1461 D_processinput = PasswordProcessInput;
1462 AddStr("Screen password: ");
1465 static void
1466 PasswordProcessInput(ibuf, ilen)
1467 char *ibuf;
1468 int ilen;
1470 struct pwdata *pwdata;
1471 int c, l;
1472 char *up;
1473 int pid = D_userpid;
1475 pwdata = (struct pwdata *)D_processinputdata;
1476 l = pwdata->l;
1477 while (ilen-- > 0)
1479 c = *(unsigned char *)ibuf++;
1480 if (c == '\r' || c == '\n')
1482 up = D_user->u_password;
1483 pwdata->buf[l] = 0;
1484 if (strncmp(crypt(pwdata->buf, up), up, strlen(up)))
1486 /* uh oh, user failed */
1487 bzero(pwdata->buf, sizeof(pwdata->buf));
1488 AddStr("\r\nPassword incorrect.\r\n");
1489 D_processinputdata = 0; /* otherwise freed by FreeDis */
1490 FreeDisplay();
1491 Msg(0, "Illegal reattach attempt from terminal %s.", pwdata->m.m_tty);
1492 free(pwdata);
1493 Kill(pid, SIG_BYE);
1494 return;
1496 /* great, pw matched, all is fine */
1497 bzero(pwdata->buf, sizeof(pwdata->buf));
1498 AddStr("\r\n");
1499 D_processinputdata = 0;
1500 D_processinput = ProcessInput;
1501 if (pwdata->m.type == MSG_ATTACH)
1502 FinishAttach(&pwdata->m);
1503 else
1504 FinishDetach(&pwdata->m);
1505 free(pwdata);
1506 return;
1508 if (c == Ctrl('c'))
1510 AddStr("\r\n");
1511 FreeDisplay();
1512 Kill(pid, SIG_BYE);
1513 return;
1515 if (c == '\b' || c == 0177)
1517 if (l > 0)
1518 l--;
1519 continue;
1521 if (c == Ctrl('u'))
1523 l = 0;
1524 continue;
1526 if (l < (int)sizeof(pwdata->buf) - 1)
1527 pwdata->buf[l++] = c;
1529 pwdata->l = l;
1531 #endif
1533 static void
1534 DoCommandMsg(mp)
1535 struct msg *mp;
1537 char *args[MAXARGS];
1538 int argl[MAXARGS];
1539 int n, *lp;
1540 register char **pp = args, *p = mp->m.command.cmd;
1541 struct acluser *user;
1542 #ifdef MULTIUSER
1543 extern struct acluser *EffectiveAclUser; /* acls.c */
1544 #else
1545 extern struct acluser *users; /* acls.c */
1546 #endif
1548 lp = argl;
1549 n = mp->m.command.nargs;
1550 if (n > MAXARGS - 1)
1551 n = MAXARGS - 1;
1552 for (; n > 0; n--)
1554 *pp++ = p;
1555 *lp = strlen(p);
1556 p += *lp++ + 1;
1558 *pp = 0;
1559 #ifdef MULTIUSER
1560 user = *FindUserPtr(mp->m.attach.auser);
1561 if (user == 0)
1563 Msg(0, "Unknown user %s tried to send a command!", mp->m.attach.auser);
1564 return;
1566 #else
1567 user = users;
1568 #endif
1569 #ifdef PASSWORD
1570 if (user->u_password && *user->u_password)
1572 Msg(0, "User %s has a password, cannot use -X option.", mp->m.attach.auser);
1573 return;
1575 #endif
1576 if (!display)
1577 for (display = displays; display; display = display->d_next)
1578 if (D_user == user)
1579 break;
1580 for (fore = windows; fore; fore = fore->w_next)
1581 if (!TTYCMP(mp->m_tty, fore->w_tty))
1583 if (!display)
1584 display = fore->w_layer.l_cvlist ? fore->w_layer.l_cvlist->c_display : 0;
1585 break;
1587 if (!display)
1588 display = displays; /* sigh */
1589 if (*mp->m.command.preselect)
1591 int i = -1;
1592 if (strcmp(mp->m.command.preselect, "-"))
1593 i = WindowByNoN(mp->m.command.preselect);
1594 fore = i >= 0 ? wtab[i] : 0;
1596 else if (!fore)
1598 if (display && D_user == user)
1599 fore = Layer2Window(display->d_forecv->c_layer);
1600 if (!fore)
1602 fore = user->u_detachwin >= 0 ? wtab[user->u_detachwin] : 0;
1603 fore = FindNiceWindow(fore, 0);
1606 #ifdef MULTIUSER
1607 EffectiveAclUser = user;
1608 #endif
1609 if (*args)
1611 char *oldrcname = rc_name;
1612 rc_name = "-X";
1613 debug3("Running command on display %x window %x (%d)\n", display, fore, fore ? fore->w_number : -1);
1614 flayer = fore ? &fore->w_layer : 0;
1615 if (fore && fore->w_savelayer && (fore->w_blocked || fore->w_savelayer->l_cvlist == 0))
1616 flayer = fore->w_savelayer;
1617 DoCommand(args, argl);
1618 rc_name = oldrcname;
1620 #ifdef MULTIUSER
1621 EffectiveAclUser = 0;
1622 #endif
1625 #ifndef NAMEDPIPE
1628 SendAttachMsg(s, m, fd)
1629 int s;
1630 struct msg *m;
1631 int fd;
1633 int r;
1634 struct msghdr msg;
1635 struct iovec iov;
1636 char buf[CMSG_SPACE(sizeof(int))];
1637 struct cmsghdr *cmsg;
1639 iov.iov_base = (char *)m;
1640 iov.iov_len = sizeof(*m);
1641 bzero(&msg, sizeof(msg));
1642 msg.msg_name = 0;
1643 msg.msg_namelen = 0;
1644 msg.msg_iov = &iov;
1645 msg.msg_iovlen = 1;
1646 msg.msg_control = buf;
1647 msg.msg_controllen = sizeof(buf);
1648 cmsg = CMSG_FIRSTHDR(&msg);
1649 cmsg->cmsg_level = SOL_SOCKET;
1650 cmsg->cmsg_type = SCM_RIGHTS;
1651 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
1652 bcopy(&fd, CMSG_DATA(cmsg), sizeof(int));
1653 msg.msg_controllen = cmsg->cmsg_len;
1654 while(1)
1656 r = sendmsg(s, &msg, 0);
1657 if (r == -1 && errno == EINTR)
1658 continue;
1659 if (r == -1)
1660 return -1;
1661 return 0;
1665 #endif