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
10 *
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.
15 *
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.
20 *
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 * https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
25 *
26 ****************************************************************
27 */
28
29 #include "config.h"
30 #include <stdbool.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 # include <sys/socket.h>
37 # ifdef _OpenBSD_
38 # include <sys/uio.h>
39 # endif
40 # include <sys/un.h>
41
42 #ifndef SIGINT
43 # include <signal.h>
44 #endif
45
46 #include "screen.h"
47
48 #ifdef HAVE_DIRENT_H
49 # include <dirent.h>
50 #else
51 # include <sys/dir.h>
52 # define dirent direct
53 #endif
54
55 #ifndef CMSG_LEN
56 #define CMSG_LEN(length) ((_CMSG_DATA_ALIGN(sizeof(struct cmsghdr))) + (length))
57 #endif
58 #ifndef CMSG_SPACE
59 #define CMSG_SPACE(length) ((_CMSG_DATA_ALIGN(sizeof(struct cmsghdr))) + (_CMSG_DATA_ALIGN(length)))
60 #endif
61
62 #include "extern.h"
63 #include "list_generic.h"
64
65 static int CheckPid __P((int));
66 static void ExecCreate __P((struct msg *));
67 static void DoCommandMsg __P((struct msg *));
68 #if defined(_SEQUENT_)
69 # define connect sconnect /* _SEQUENT_ has braindamaged connect */
70 static int sconnect __P((int, struct sockaddr *, int));
71 #endif
72 static void FinishAttach __P((struct msg *));
73 static void FinishDetach __P((struct msg *));
74 static void AskPassword __P((struct msg *));
75
76
77 extern char *RcFileName, *extra_incap, *extra_outcap;
78 extern int ServerSocket, real_uid, real_gid, eff_uid, eff_gid;
79 extern int dflag, iflag, rflag, lsflag, quietflag, wipeflag, xflag;
80 extern int queryflag;
81 extern char *attach_tty, *LoginName, HostName[];
82 extern struct display *display, *displays;
83 extern struct win *fore, **wtab, *console_window, *windows;
84 extern struct layer *flayer;
85 extern struct layout *layout_attach, *layout_last, layout_last_marker;
86 extern struct NewWindow nwin_undef;
87 #ifdef MULTIUSER
88 extern char *multi;
89 #endif
90 extern int maxwin;
91
92 extern char *getenv();
93
94 extern char SockPath[];
95 extern struct event serv_read;
96 extern char *rc_name;
97 extern struct comm comms[];
98
99 #ifdef MULTIUSER
100 # define SOCKMODE (S_IWRITE | S_IREAD | (displays ? S_IEXEC : 0) | (multi ? 1 : 0))
101 #else
102 # define SOCKMODE (S_IWRITE | S_IREAD | (displays ? S_IEXEC : 0))
103 #endif
104
105
106 /*
107 * Socket directory manager
108 *
109 * fdp: pointer to store the first good socket.
110 * nfoundp: pointer to store the number of sockets found matching.
111 * notherp: pointer to store the number of sockets not matching.
112 * match: string to match socket name.
113 *
114 * The socket directory must be in SockPath!
115 * The global variables LoginName, multi, rflag, xflag, dflag,
116 * quietflag, SockPath are used.
117 *
118 * The first good socket is stored in fdp and its name is
119 * appended to SockPath.
120 * If none exists or fdp is NULL SockPath is not changed.
121 *
122 * Returns: number of good sockets.
123 *
124 */
125
126 int
FindSocket(fdp,nfoundp,notherp,match,is_sock)127 FindSocket(fdp, nfoundp, notherp, match, is_sock)
128 int *fdp;
129 int *nfoundp, *notherp;
130 char *match;
131 bool *is_sock;
132 {
133 DIR *dirp;
134 struct dirent *dp;
135 struct stat st;
136 int mode;
137 int sdirlen;
138 int matchlen = 0;
139 char *name, *n;
140 int firsts = -1, sockfd;
141 char *firstn = NULL;
142 int nfound = 0, ngood = 0, ndead = 0, nwipe = 0, npriv = 0;
143 int nperfect = 0;
144 struct sent
145 {
146 struct sent *next;
147 int mode;
148 char *name;
149 } *slist, **slisttail, *sent, *nsent;
150
151 if (match)
152 {
153 matchlen = strlen(match);
154 #ifdef NAME_MAX
155 if (matchlen > NAME_MAX)
156 matchlen = NAME_MAX;
157 #endif
158 }
159
160 /*
161 * SockPath contains the socket directory.
162 * At the end of FindSocket the socket name will be appended to it.
163 * Thus FindSocket() can only be called once!
164 */
165 sdirlen = strlen(SockPath);
166
167 #ifdef USE_SETEUID
168 xseteuid(real_uid);
169 xsetegid(real_gid);
170 #endif
171
172 if ((dirp = opendir(SockPath)) == 0)
173 Panic(errno, "Cannot opendir %s", SockPath);
174
175 slist = 0;
176 slisttail = &slist;
177 while ((dp = readdir(dirp)))
178 {
179 int cmatch = 0;
180 name = dp->d_name;
181 debug1("- %s\n", name);
182 if (*name == 0 || *name == '.' || strlen(name) > 2*MAXSTR)
183 continue;
184 if (matchlen)
185 {
186 n = name;
187 /* if we don't want to match digits. Skip them */
188 if ((*match <= '0' || *match > '9') && (*n > '0' && *n <= '9'))
189 {
190 while (*n >= '0' && *n <= '9')
191 n++;
192 if (*n == '.')
193 n++;
194 }
195 /* the tty prefix is optional */
196 if (strncmp(match, "tty", 3) && strncmp(n, "tty", 3) == 0)
197 n += 3;
198 if (strncmp(match, n, matchlen))
199 {
200 if (n == name && *match > '0' && *match <= '9')
201 {
202 while (*n >= '0' && *n <= '9')
203 n++;
204 if (*n == '.')
205 n++;
206 if (strncmp(match, n, matchlen))
207 continue;
208 }
209 else
210 continue;
211 }
212 else
213 cmatch = (*(n + matchlen) == 0);
214 debug1(" -> matched %s\n", match);
215 }
216 sprintf(SockPath + sdirlen, "/%s", name);
217
218 debug1("stat %s\n", SockPath);
219 errno = 0;
220 debug2("uid = %d, gid = %d\n", getuid(), getgid());
221 debug2("euid = %d, egid = %d\n", geteuid(), getegid());
222 if (stat(SockPath, &st))
223 {
224 debug1("errno = %d\n", errno);
225 continue;
226 }
227
228 *is_sock = S_ISSOCK(st.st_mode);
229 if (!(*is_sock) && !S_ISFIFO(st.st_mode))
230 continue;
231
232 debug2("st.st_uid = %d, real_uid = %d\n", st.st_uid, real_uid);
233 #ifdef SOCKDIR /* if SOCKDIR is not defined, the socket is in $HOME.
234 in that case it does not make sense to compare uids. */
235 if ((int)st.st_uid != real_uid)
236 continue;
237 #endif
238 mode = (int)st.st_mode & 0777;
239 debug1(" has mode 0%03o\n", mode);
240 #ifdef MULTIUSER
241 if (multi && ((mode & 0677) != 0601))
242 {
243 debug(" is not a MULTI-USER session");
244 if (strcmp(multi, LoginName))
245 {
246 debug(" and we are in a foreign directory.\n");
247 mode = -4;
248 }
249 else
250 {
251 debug(", but it is our own session.\n");
252 }
253 }
254 #endif
255 debug(" store it.\n");
256 if ((sent = (struct sent *)malloc(sizeof(struct sent))) == 0)
257 continue;
258 sent->next = 0;
259 sent->name = SaveStr(name);
260 sent->mode = mode;
261 *slisttail = sent;
262 slisttail = &sent->next;
263 nfound++;
264 sockfd = MakeClientSocket(0, *is_sock);
265 #ifdef USE_SETEUID
266 /* MakeClientSocket sets ids back to eff */
267 xseteuid(real_uid);
268 xsetegid(real_gid);
269 #endif
270 if (sockfd == -1)
271 {
272 debug2(" MakeClientSocket failed, unreachable? %d %d\n",
273 matchlen, wipeflag);
274 sent->mode = -3;
275 #ifndef SOCKDIR_IS_LOCAL_TO_HOST
276 /* Unreachable - it is dead if we detect that it's local
277 * or we specified a match
278 */
279 n = name + strlen(name) - 1;
280 while (n != name && *n != '.')
281 n--;
282 if (matchlen == 0 && !(*n == '.' && n[1] && strncmp(HostName, n + 1, strlen(n + 1)) == 0))
283 {
284 npriv++; /* a good socket that was not for us */
285 continue;
286 }
287 #endif
288 ndead++;
289 sent->mode = -1;
290 if (wipeflag)
291 {
292 if (unlink(SockPath) == 0)
293 {
294 sent->mode = -2;
295 nwipe++;
296 }
297 }
298 continue;
299 }
300
301 mode &= 0776;
302 /* Shall we connect ? */
303 debug2(" connecting: mode=%03o, rflag=%d, ", mode, rflag);
304 debug2("xflag=%d, dflag=%d ?\n", xflag, dflag);
305
306 /*
307 * mode 600: socket is detached.
308 * mode 700: socket is attached.
309 * xflag implies rflag here.
310 *
311 * fail, when socket mode mode is not 600 or 700
312 * fail, when we want to detach w/o reattach, but it already is detached.
313 * fail, when we only want to attach, but mode 700 and not xflag.
314 * fail, if none of dflag, rflag, xflag is set.
315 */
316 if ((mode != 0700 && mode != 0600) ||
317 (dflag && !rflag && !xflag && mode == 0600) ||
318 (!dflag && rflag && mode == 0700 && !xflag) ||
319 (!dflag && !rflag && !xflag))
320 {
321 close(sockfd);
322 debug(" no!\n");
323 npriv++; /* a good socket that was not for us */
324 continue;
325 }
326 ngood++;
327 if (cmatch)
328 nperfect++;
329 if (fdp && (firsts == -1 || (cmatch && nperfect == 1)))
330 {
331 if (firsts != -1)
332 close(firsts);
333 firsts = sockfd;
334 firstn = sent->name;
335 debug(" taken.\n");
336 }
337 else
338 {
339 debug(" discarded.\n");
340 close(sockfd);
341 }
342 }
343 (void)closedir(dirp);
344 if (!lsflag && nperfect == 1)
345 ngood = nperfect;
346 if (nfound && (lsflag || ngood != 1) && !quietflag)
347 {
348 switch(ngood)
349 {
350 case 0:
351 Msg(0, nfound > 1 ? "There are screens on:" : "There is a screen on:");
352 break;
353 case 1:
354 Msg(0, nfound > 1 ? "There are several screens on:" : "There is a suitable screen on:");
355 break;
356 default:
357 Msg(0, "There are several suitable screens on:");
358 break;
359 }
360 for (sent = slist; sent; sent = sent->next)
361 {
362 switch (sent->mode)
363 {
364 case 0700:
365 printf("\t%s\t(Attached)\n", sent->name);
366 break;
367 case 0600:
368 printf("\t%s\t(Detached)\n", sent->name);
369 break;
370 #ifdef MULTIUSER
371 case 0701:
372 printf("\t%s\t(Multi, attached)\n", sent->name);
373 break;
374 case 0601:
375 printf("\t%s\t(Multi, detached)\n", sent->name);
376 break;
377 #endif
378 case -1:
379 /* No trigraphs here! */
380 printf("\t%s\t(Dead ?%c?)\n", sent->name, '?');
381 break;
382 case -2:
383 printf("\t%s\t(Removed)\n", sent->name);
384 break;
385 case -3:
386 printf("\t%s\t(Remote or dead)\n", sent->name);
387 break;
388 case -4:
389 printf("\t%s\t(Private)\n", sent->name);
390 break;
391 }
392 }
393 }
394 if (ndead && !quietflag)
395 {
396 char *m = "Remove dead screens with 'screen -wipe'.";
397 if (wipeflag)
398 Msg(0, "%d socket%s wiped out.", nwipe, nwipe > 1 ? "s" : "");
399 else
400 Msg(0, m, ndead > 1 ? "s" : "", ndead > 1 ? "" : "es"); /* other args for nethack */
401 }
402 if (firsts != -1)
403 {
404 sprintf(SockPath + sdirlen, "/%s", firstn);
405 *fdp = firsts;
406 }
407 else
408 SockPath[sdirlen] = 0;
409 for (sent = slist; sent; sent = nsent)
410 {
411 nsent = sent->next;
412 free(sent->name);
413 free((char *)sent);
414 }
415 #ifdef USE_SETEUID
416 xseteuid(eff_uid);
417 xsetegid(eff_gid);
418 #endif
419 if (notherp)
420 *notherp = npriv;
421 if (nfoundp)
422 *nfoundp = nfound - nwipe;
423 return ngood;
424 }
425
426 /* FIFO (legacy mode) */
427 static int
MakeServerFifo()428 MakeServerFifo()
429 {
430 register int s;
431 struct stat st;
432
433 #ifdef USE_SETEUID
434 xseteuid(real_uid);
435 xsetegid(real_gid);
436 #endif
437 s = open(SockPath, O_WRONLY | O_NONBLOCK);
438 if (s >= 0)
439 {
440 debug("huii, my fifo already exists??\n");
441 if (quietflag)
442 {
443 Kill(D_userpid, SIG_BYE);
444 eexit(11);
445 }
446
447 Msg(0, "There is already a screen running on %s.", Filename(SockPath));
448
449 if (stat(SockPath, &st) < 0)
450 Panic(errno, "stat");
451
452 #ifdef SOCKDIR /* if SOCKDIR is not defined, the socket is in $HOME. \
453 in that case it does not make sense to compare uids. */
454 if ((int)st.st_uid != real_uid)
455 Panic(0, "Unfortunately you are not its owner.");
456 #endif
457 if ((st.st_mode & 0700) == 0600)
458 Panic(0, "To resume it, use \"screen -r\"");
459 else
460 Panic(0, "It is not detached.");
461 /* NOTREACHED */
462 }
463 # ifdef USE_SETEUID
464 (void) unlink(SockPath);
465 if (mkfifo(SockPath, SOCKMODE) < 0)
466 Panic(0, "mkfifo %s failed", SockPath);
467 # ifdef BROKEN_PIPE
468 s = open(SockPath, O_RDWR | O_NONBLOCK, 0);
469 # else
470 s = open(SockPath, O_RDONLY | O_NONBLOCK, 0);
471 # endif
472 if (s < 0)
473 Panic(errno, "open fifo %s", SockPath);
474
475 xseteuid(eff_uid);
476 xsetegid(eff_gid);
477
478 return s;
479
480 # else /* !USE_SETEUID */
481 if (UserContext() > 0)
482 {
483 (void) unlink(SockPath);
484 UserReturn(mkfifo(SockPath, SOCKMODE));
485 }
486 if (UserStatus())
487 Panic(0, "mkfifo %s failed", SockPath);
488 # ifdef BROKEN_PIPE
489 s = secopen(SockPath, O_RDWR | O_NONBLOCK, 0);
490 # else
491 s = secopen(SockPath, O_RDONLY | O_NONBLOCK, 0);
492 # endif
493 if (s < 0)
494 Panic(errno, "open fifo %s", SockPath);
495
496 return s;
497 # endif /* !USE_SETEUID */
498 }
499
500 static int
MakeClientFifo(err)501 MakeClientFifo(err)
502 int err;
503 {
504 register int s = 0;
505
506 s = secopen(SockPath, O_WRONLY | O_NONBLOCK, 0);
507 if (s >= 0)
508 {
509 (void) fcntl(s, F_SETFL, 0);
510 return s;
511 }
512
513 if (err)
514 Msg(errno, "%s", SockPath);
515 debug2("MakeClientSocket() open %s failed (%d)\n", SockPath, errno);
516
517 return -1;
518 }
519
520 /* Unix Domain Sockets */
521 static int
MakeServerUnixSocket()522 MakeServerUnixSocket()
523 {
524 register int s;
525 struct sockaddr_un a;
526 struct stat st;
527
528 s = socket(AF_UNIX, SOCK_STREAM, 0);
529 if (s < 0)
530 Panic(errno, "socket");
531
532 a.sun_family = AF_UNIX;
533 strncpy(a.sun_path, SockPath, sizeof(a.sun_path));
534 a.sun_path[sizeof(a.sun_path) - 1] = 0;
535
536 # ifdef USE_SETEUID
537 xseteuid(real_uid);
538 xsetegid(real_gid);
539 # endif
540 if (connect(s, (struct sockaddr *) &a, strlen(SockPath) + 2) != -1)
541 {
542 debug("oooooh! socket already is alive!\n");
543 if (quietflag)
544 {
545 Kill(D_userpid, SIG_BYE);
546 /*
547 * oh, well. nobody receives that return code. papa
548 * dies by signal.
549 */
550 eexit(11);
551 }
552 Msg(0, "There is already a screen running on %s.", Filename(SockPath));
553
554 if (stat(SockPath, &st) < 0)
555 Panic(errno, "stat");
556
557 #ifdef SOCKDIR /* if SOCKDIR is not defined, the socket is in $HOME. \
558 in that case it does not make sense to compare uids. */
559 if (st.st_uid != real_uid)
560 Panic(0, "Unfortunately you are not its owner.");
561 #endif
562 if ((st.st_mode & 0700) == 0600)
563 Panic(0, "To resume it, use \"screen -r\"");
564 else
565 Panic(0, "It is not detached.");
566 /* NOTREACHED */
567 }
568
569 #if defined(m88k) || defined(sysV68)
570 close(s); /* we get bind: Invalid argument if this is not done */
571 s = socket(AF_UNIX, SOCK_STREAM, 0);
572 if (s < 0)
573 Panic(errno, "reopen socket");
574 #endif
575 (void) unlink(SockPath);
576 if (bind(s, (struct sockaddr *) & a, strlen(SockPath) + 2) == -1)
577 Panic(errno, "bind (%s)", SockPath);
578 #ifdef SOCK_NOT_IN_FS
579 {
580 int f = secopen(SockPath, O_RDWR | O_CREAT, SOCKMODE);
581 if (f < 0)
582 Panic(errno, "shadow socket open");
583 close(f);
584 }
585 #else
586 chmod(SockPath, SOCKMODE);
587 #ifndef USE_SETEUID
588 chown(SockPath, real_uid, real_gid);
589 #endif
590 #endif /* SOCK_NOT_IN_FS */
591 if (listen(s, 5) == -1)
592 Panic(errno, "listen");
593 #ifdef F_SETOWN
594 fcntl(s, F_SETOWN, getpid());
595 debug1("Serversocket owned by %d\n", fcntl(s, F_GETOWN, 0));
596 #endif /* F_SETOWN */
597 #ifdef USE_SETEUID
598 xseteuid(eff_uid);
599 xsetegid(eff_gid);
600 #endif
601 return s;
602 }
603
604 static int
MakeClientUnixSocket(err)605 MakeClientUnixSocket(err)
606 int err;
607 {
608 register int s;
609 struct sockaddr_un a;
610
611 s = socket(AF_UNIX, SOCK_STREAM, 0);
612 if (s < 0)
613 Panic(errno, "socket");
614
615 a.sun_family = AF_UNIX;
616 strncpy(a.sun_path, SockPath, sizeof(a.sun_path));
617 a.sun_path[sizeof(a.sun_path) - 1] = 0;
618 #ifdef USE_SETEUID
619 xseteuid(real_uid);
620 xsetegid(real_gid);
621 #else
622 if (access(SockPath, W_OK))
623 {
624 if (err)
625 Msg(errno, "%s", SockPath);
626 debug2("MakeClientSocket: access(%s): %d.\n", SockPath, errno);
627 close(s);
628 return -1;
629 }
630 #endif
631 if (connect(s, (struct sockaddr *)&a, strlen(SockPath) + 2) == -1)
632 {
633 if (err)
634 Msg(errno, "%s: connect", SockPath);
635 debug("MakeClientSocket: connect failed.\n");
636 close(s);
637 s = -1;
638 }
639 #ifdef USE_SETEUID
640 xseteuid(eff_uid);
641 xsetegid(eff_gid);
642 #endif
643 return s;
644 }
645
646 int
MakeServerSocket(socket)647 MakeServerSocket(socket)
648 bool socket;
649 {
650 if (socket)
651 return MakeServerUnixSocket();
652
653 return MakeServerFifo();
654 }
655
656 int
MakeClientSocket(err,socket)657 MakeClientSocket(err, socket)
658 int err;
659 bool socket;
660 {
661 if (socket)
662 return MakeClientUnixSocket(err);
663
664 return MakeClientFifo(err);
665 }
666
667 /*
668 **
669 ** Message send and receive routines
670 **
671 */
672
673 void
SendCreateMsg(sty,nwin)674 SendCreateMsg(sty, nwin)
675 char *sty;
676 struct NewWindow *nwin;
677 {
678 int s;
679 struct msg m;
680 register char *p;
681 register int len, n;
682 char **av;
683 bool is_socket;
684
685 #ifdef NAME_MAX
686 if (strlen(sty) > NAME_MAX)
687 sty[NAME_MAX] = 0;
688 #endif
689 if (strlen(sty) > 2 * MAXSTR - 1)
690 sty[2 * MAXSTR - 1] = 0;
691 sprintf(SockPath + strlen(SockPath), "/%s", sty);
692 is_socket = IsSocket(SockPath);
693 if ((s = MakeClientSocket(1, is_socket)) == -1)
694 exit(1);
695 debug1("SendCreateMsg() to '%s'\n", SockPath);
696 bzero((char *)&m, sizeof(m));
697 m.type = MSG_CREATE;
698 strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1);
699 m.m_tty[sizeof(m.m_tty) - 1] = 0;
700 p = m.m.create.line;
701 n = 0;
702 if (nwin->args != nwin_undef.args)
703 for (av = nwin->args; *av && n < MAXARGS - 1; ++av, ++n)
704 {
705 len = strlen(*av) + 1;
706 if (p + len >= m.m.create.line + sizeof(m.m.create.line) - 1)
707 break;
708 strcpy(p, *av);
709 p += len;
710 }
711 if (nwin->aka != nwin_undef.aka && p + strlen(nwin->aka) + 1 < m.m.create.line + sizeof(m.m.create.line))
712 strcpy(p, nwin->aka);
713 else
714 *p = '\0';
715 m.m.create.nargs = n;
716 m.m.create.aflag = nwin->aflag;
717 m.m.create.flowflag = nwin->flowflag;
718 m.m.create.lflag = nwin->lflag;
719 m.m.create.hheight = nwin->histheight;
720 if (getcwd(m.m.create.dir, sizeof(m.m.create.dir)) == 0)
721 {
722 Msg(errno, "getcwd");
723 goto end;
724 }
725 if (nwin->term != nwin_undef.term)
726 strncpy(m.m.create.screenterm, nwin->term, MAXTERMLEN);
727 m.m.create.screenterm[MAXTERMLEN] = '\0';
728 m.protocol_revision = MSG_REVISION;
729 debug1("SendCreateMsg writing '%s'\n", m.m.create.line);
730 if (write(s, (char *) &m, sizeof m) != sizeof m)
731 Msg(errno, "write");
732
733 end:
734 close(s);
735 }
736
737 int
SendErrorMsg(tty,buf)738 SendErrorMsg(tty, buf)
739 char *tty, *buf;
740 {
741 int s;
742 struct msg m;
743 bool is_socket;
744
745 debug2("SendErrorMsg: %s %s\n", tty, buf);
746 strncpy(m.m.message, buf, sizeof(m.m.message) - 1);
747 m.m.message[sizeof(m.m.message) - 1] = 0;
748 is_socket = IsSocket(SockPath);
749 s = MakeClientSocket(0, is_socket);
750 if (s < 0)
751 return -1;
752 m.type = MSG_ERROR;
753 strncpy(m.m_tty, tty, sizeof(m.m_tty) - 1);
754 m.m_tty[sizeof(m.m_tty) - 1] = 0;
755 m.protocol_revision = MSG_REVISION;
756 debug1("SendErrorMsg(): writing to '%s'\n", SockPath);
757 (void) write(s, (char *) &m, sizeof m);
758 close(s);
759 return 0;
760 }
761
762 static void
ExecCreate(mp)763 ExecCreate(mp)
764 struct msg *mp;
765 {
766 struct NewWindow nwin;
767 char *args[MAXARGS];
768 register int n;
769 register char **pp = args, *p = mp->m.create.line;
770 char buf[20];
771
772 nwin = nwin_undef;
773 n = mp->m.create.nargs;
774 if (n > MAXARGS - 1)
775 n = MAXARGS - 1;
776 /* ugly hack alert... should be done by the frontend! */
777 if (n)
778 {
779 int l, num;
780
781 l = strlen(p);
782 if (IsNumColon(p, 10, buf, sizeof(buf)))
783 {
784 if (*buf)
785 nwin.aka = buf;
786 num = atoi(p);
787 if (num < 0 || num > maxwin - 1)
788 num = 0;
789 nwin.StartAt = num;
790 p += l + 1;
791 n--;
792 }
793 }
794 for (; n > 0; n--)
795 {
796 *pp++ = p;
797 p += strlen(p) + 1;
798 }
799 *pp = 0;
800 if (*p)
801 nwin.aka = p;
802 if (*args)
803 nwin.args = args;
804 nwin.aflag = mp->m.create.aflag;
805 nwin.flowflag = mp->m.create.flowflag;
806 if (*mp->m.create.dir)
807 nwin.dir = mp->m.create.dir;
808 nwin.lflag = mp->m.create.lflag;
809 nwin.histheight = mp->m.create.hheight;
810 if (*mp->m.create.screenterm)
811 nwin.term = mp->m.create.screenterm;
812 MakeWindow(&nwin);
813 }
814
815 static int
CheckPid(pid)816 CheckPid(pid)
817 int pid;
818 {
819 debug1("Checking pid %d\n", pid);
820 if (pid < 2)
821 return -1;
822 if (eff_uid == real_uid)
823 return kill(pid, 0);
824 if (UserContext() > 0)
825 UserReturn(kill(pid, 0));
826 return UserStatus();
827 }
828
829 #ifdef hpux
830 /*
831 * From: "F. K. Bruner" <napalm@ugcs.caltech.edu>
832 * From: "Dan Egnor" <egnor@oracorp.com> Tue Aug 10 06:56:45 1993
833 * The problem is that under HPUX (and possibly other systems too) there are
834 * two equivalent device files for each pty/tty device:
835 * /dev/ttyxx == /dev/pty/ttyxx
836 * /dev/ptyxx == /dev/ptym/ptyxx
837 * I didn't look into the exact specifics, but I've run across this problem
838 * before: Even if you open /dev/ttyxx as fds 0 1 & 2 for a process, if that
839 * process calls the system to determine its tty, it'll get /dev/pty/ttyxx.
840 *
841 * Earlier versions seemed to work -- wonder what they did.
842 */
843 static int
ttycmp(s1,s2)844 ttycmp(s1, s2)
845 char *s1, *s2;
846 {
847 if (strlen(s1) > 5) s1 += strlen(s1) - 5;
848 if (strlen(s2) > 5) s2 += strlen(s2) - 5;
849 return strcmp(s1, s2);
850 }
851 # define TTYCMP(a, b) ttycmp(a, b)
852 #else
853 # define TTYCMP(a, b) strcmp(a, b)
854 #endif
855
856 static int
CreateTempDisplay(m,recvfd,wi)857 CreateTempDisplay(m, recvfd, wi)
858 struct msg *m;
859 int recvfd;
860 struct win *wi;
861 {
862 int pid;
863 int attach;
864 char *user;
865 int i;
866 struct mode Mode;
867 struct display *olddisplays = displays;
868
869 switch (m->type)
870 {
871 case MSG_CONT:
872 case MSG_ATTACH:
873 pid = m->m.attach.apid;
874 user = m->m.attach.auser;
875 attach = 1;
876 break;
877 #ifdef REMOTE_DETACH
878 case MSG_DETACH:
879 # ifdef POW_DETACH
880 case MSG_POW_DETACH:
881 # endif /* POW_DETACH */
882 pid = m->m.detach.dpid;
883 user = m->m.detach.duser;
884 attach = 0;
885 break;
886 #endif
887 default:
888 return -1;
889 }
890
891 if (CheckPid(pid))
892 {
893 Msg(0, "Attach attempt with bad pid(%d)!", pid);
894 return -1;
895 }
896 if (recvfd != -1)
897 {
898 int ret;
899 char ttyname_in_ns[MAXPATHLEN];
900 char *myttyname;
901
902 i = recvfd;
903 recvfd = -1;
904 memset(&ttyname_in_ns, 0, sizeof(ttyname_in_ns));
905 errno = 0;
906 myttyname = GetPtsPathOrSymlink(i);
907 if (myttyname && errno == ENODEV)
908 {
909 ret = readlink(myttyname, ttyname_in_ns, sizeof(ttyname_in_ns));
910 if (ret < 0 || (size_t)ret >= sizeof(ttyname_in_ns))
911 {
912 Msg(errno, "Could not perform necessary sanity checks on pts device.");
913 close(i);
914 Kill(pid, SIG_BYE);
915 return -1;
916 }
917 if (strcmp(ttyname_in_ns, m->m_tty))
918 {
919 Msg(errno, "Attach: passed fd does not match tty: %s - %s!", ttyname_in_ns, m->m_tty[0] != '\0' ? m->m_tty : "(null)");
920 close(i);
921 Kill(pid, SIG_BYE);
922 return -1;
923 }
924 /* m->m_tty so far contains the actual name of the pts device in the
925 * its (e.g. /dev/pts/0). This name however is not valid in the
926 * current namespace. So after we verified that the symlink returned
927 * by GetPtsPathOrSymlink() refers to the same pts device in this
928 * namespace we need to update m->m_tty to use that symlink for all
929 * future operations.
930 */
931 strncpy(m->m_tty, myttyname, sizeof(m->m_tty) - 1);
932 m->m_tty[sizeof(m->m_tty) - 1] = 0;
933 }
934 else if (myttyname == 0 || strcmp(myttyname, m->m_tty))
935 {
936 Msg(errno, "Attach: passed fd does not match tty: %s - %s!", m->m_tty, myttyname ? myttyname : "NULL");
937 close(i);
938 Kill(pid, SIG_BYE);
939 return -1;
940 }
941 }
942 else if ((i = secopen(m->m_tty, O_RDWR | O_NONBLOCK, 0)) < 0)
943 {
944 Msg(errno, "Attach: Could not open %s!", m->m_tty);
945 Kill(pid, SIG_BYE);
946 return -1;
947 }
948 #ifdef MULTIUSER
949 if (attach)
950 Kill(pid, SIGCONT);
951 #endif
952
953 #if defined(ultrix) || defined(pyr) || defined(NeXT)
954 brktty(i); /* for some strange reason this must be done */
955 #endif
956
957 if (attach)
958 {
959 if (display || wi)
960 {
961 write(i, "Attaching from inside of screen?\n", 33);
962 close(i);
963 Kill(pid, SIG_BYE);
964 Msg(0, "Attach msg ignored: coming from inside.");
965 return -1;
966 }
967
968 #ifdef MULTIUSER
969 if (strcmp(user, LoginName))
970 if (*FindUserPtr(user) == 0)
971 {
972 write(i, "Access to session denied.\n", 26);
973 close(i);
974 Kill(pid, SIG_BYE);
975 Msg(0, "Attach: access denied for user %s.", user);
976 return -1;
977 }
978 #endif
979
980 debug2("RecMsg: apid %d is o.k. and we just opened '%s'\n", pid, m->m_tty);
981 #ifndef MULTI
982 if (displays)
983 {
984 write(i, "Screen session in use.\n", 23);
985 close(i);
986 Kill(pid, SIG_BYE);
987 return -1;
988 }
989 #endif
990 }
991
992 /* create new display */
993 GetTTY(i, &Mode);
994 if (MakeDisplay(user, m->m_tty, attach ? m->m.attach.envterm : "", i, pid, &Mode) == 0)
995 {
996 write(i, "Could not make display.\n", 24);
997 close(i);
998 Msg(0, "Attach: could not make display for user %s", user);
999 Kill(pid, SIG_BYE);
1000 return -1;
1001 }
1002 #ifdef ENCODINGS
1003 if (attach)
1004 {
1005 # ifdef UTF8
1006 D_encoding = m->m.attach.encoding == 1 ? UTF8 : m->m.attach.encoding ? m->m.attach.encoding - 1 : 0;
1007 # else
1008 D_encoding = m->m.attach.encoding ? m->m.attach.encoding - 1 : 0;
1009 # endif
1010 if (D_encoding < 0 || !EncodingName(D_encoding))
1011 D_encoding = 0;
1012 }
1013 #endif
1014
1015 if (iflag && olddisplays)
1016 {
1017 iflag = 0;
1018 #if defined(TERMIO) || defined(POSIX)
1019 olddisplays->d_NewMode.tio.c_cc[VINTR] = VDISABLE;
1020 olddisplays->d_NewMode.tio.c_lflag &= ~ISIG;
1021 #else /* TERMIO || POSIX */
1022 olddisplays->d_NewMode.m_tchars.t_intrc = -1;
1023 #endif /* TERMIO || POSIX */
1024 SetTTY(olddisplays->d_userfd, &olddisplays->d_NewMode);
1025 }
1026 SetMode(&D_OldMode, &D_NewMode, D_flow, iflag);
1027 SetTTY(D_userfd, &D_NewMode);
1028 if (fcntl(D_userfd, F_SETFL, FNBLOCK))
1029 Msg(errno, "Warning: NBLOCK fcntl failed");
1030 return 0;
1031 }
1032
1033 void
ReceiveMsg()1034 ReceiveMsg()
1035 {
1036 int left, len;
1037 static struct msg m;
1038 char *p;
1039 int ns = ServerSocket;
1040 struct win *wi;
1041 int recvfd = -1;
1042 struct acluser *user;
1043 bool is_socket;
1044
1045 /* Socket specific variables. */
1046 struct sockaddr_un a;
1047 struct msghdr msg;
1048 struct iovec iov;
1049 char control[1024];
1050
1051 is_socket = IsSocket(SockPath);
1052 if (!is_socket)
1053 {
1054 debug("Ha, there was someone knocking on my fifo??\n");
1055 if (fcntl(ServerSocket, F_SETFL, 0) == -1)
1056 Panic(errno, "BLOCK fcntl");
1057 p = (char *)&m;
1058 left = sizeof(m);
1059 }
1060 else
1061 {
1062 len = sizeof(a);
1063 debug("Ha, there was someone knocking on my socket??\n");
1064 if ((ns = accept(ns, (struct sockaddr *)&a, (void *)&len)) < 0)
1065 {
1066 Msg(errno, "accept");
1067 return;
1068 }
1069
1070 p = (char *)&m;
1071 left = sizeof(m);
1072 bzero(&msg, sizeof(msg));
1073 iov.iov_base = &m;
1074 iov.iov_len = left;
1075 msg.msg_iov = &iov;
1076 msg.msg_iovlen = 1;
1077 msg.msg_controllen = sizeof(control);
1078 msg.msg_control = &control;
1079 while (left > 0)
1080 {
1081 len = recvmsg(ns, &msg, 0);
1082 if (len < 0 && errno == EINTR)
1083 continue;
1084 if (len < 0)
1085 {
1086 close(ns);
1087 Msg(errno, "read");
1088 return;
1089 }
1090 if (msg.msg_controllen)
1091 {
1092 struct cmsghdr *cmsg;
1093 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
1094 cmsg = CMSG_NXTHDR(&msg, cmsg))
1095 {
1096 int cl;
1097 char *cp;
1098 if (cmsg->cmsg_level != SOL_SOCKET ||
1099 cmsg->cmsg_type != SCM_RIGHTS)
1100 continue;
1101 cp = (char *)CMSG_DATA(cmsg);
1102 cl = cmsg->cmsg_len;
1103 while (cl >= CMSG_LEN(sizeof(int)))
1104 {
1105 int passedfd;
1106 bcopy(cp, &passedfd, sizeof(int));
1107 if (recvfd >= 0 && passedfd != recvfd)
1108 close(recvfd);
1109 recvfd = passedfd;
1110 cl -= CMSG_LEN(sizeof(int));
1111 }
1112 }
1113 }
1114 p += len;
1115 left -= len;
1116 break;
1117 }
1118 }
1119
1120 while (left > 0)
1121 {
1122 len = read(ns, p, left);
1123 if (len < 0 && errno == EINTR)
1124 continue;
1125 if (len <= 0)
1126 break;
1127 p += len;
1128 left -= len;
1129 }
1130
1131 if (!is_socket)
1132 {
1133 #ifndef BROKEN_PIPE
1134 /* Reopen pipe to prevent EOFs at the select() call */
1135 close(ServerSocket);
1136 if ((ServerSocket = secopen(SockPath, O_RDONLY | O_NONBLOCK, 0)) < 0)
1137 Panic(errno, "reopen fifo %s", SockPath);
1138 evdeq(&serv_read);
1139 serv_read.fd = ServerSocket;
1140 evenq(&serv_read);
1141 #endif
1142 }
1143 else
1144 {
1145 close(ns);
1146 }
1147
1148 if (len < 0)
1149 {
1150 Msg(errno, "read");
1151 if (recvfd != -1)
1152 close(recvfd);
1153 return;
1154 }
1155 if (left > 0)
1156 {
1157 if (left != sizeof(m))
1158 Msg(0, "Message %d of %d bytes too small", left, (int)sizeof(m));
1159 else
1160 debug("No data on socket.\n");
1161 return;
1162 }
1163 if (m.protocol_revision != MSG_REVISION)
1164 {
1165 if (recvfd != -1)
1166 close(recvfd);
1167 Msg(0, "Invalid message (magic 0x%08x).", m.protocol_revision);
1168 return;
1169 }
1170
1171 debug2("*** RecMsg: type %d tty %s\n", m.type, m.m_tty);
1172 if (m.type != MSG_ATTACH && recvfd != -1)
1173 {
1174 close(recvfd);
1175 recvfd = -1;
1176 }
1177
1178 for (display = displays; display; display = display->d_next)
1179 if (TTYCMP(D_usertty, m.m_tty) == 0)
1180 break;
1181 debug2("display: %s display %sfound\n", m.m_tty, display ? "" : "not ");
1182 wi = 0;
1183 if (!display)
1184 {
1185 for (wi = windows; wi; wi = wi->w_next)
1186 if (!TTYCMP(m.m_tty, wi->w_tty))
1187 {
1188 /* XXX: hmmm, rework this? */
1189 display =
1190 wi->w_layer.l_cvlist ? wi->w_layer.l_cvlist->c_display : 0;
1191 debug2("but window %s %sfound.\n", m.m_tty,
1192 display ? "" : "(backfacing)");
1193 break;
1194 }
1195 }
1196
1197 /* Remove the status to prevent garbage on the screen */
1198 if (display && D_status)
1199 RemoveStatus();
1200
1201 if (display && !D_tcinited && m.type != MSG_HANGUP)
1202 {
1203 if (recvfd != -1)
1204 close(recvfd);
1205 return; /* ignore messages for bad displays */
1206 }
1207
1208 switch (m.type)
1209 {
1210 case MSG_WINCH:
1211 if (display)
1212 CheckScreenSize(1); /* Change fore */
1213 break;
1214 case MSG_CREATE:
1215 /*
1216 * the window that issued the create message need not be an
1217 * active
1218 * window. Then we create the window without having a display.
1219 * Resulting in another inactive window.
1220 */
1221 ExecCreate(&m);
1222 break;
1223 case MSG_CONT:
1224 if (display && D_userpid != 0 && kill(D_userpid, 0) == 0)
1225 break; /* Intruder Alert */
1226 debug2("RecMsg: apid=%d,was %d\n", m.m.attach.apid,
1227 display ? D_userpid : 0);
1228 /* FALLTHROUGH */
1229
1230 case MSG_ATTACH:
1231 if (CreateTempDisplay(&m, recvfd, wi))
1232 break;
1233 #ifdef PASSWORD
1234 if (D_user->u_password && *D_user->u_password)
1235 AskPassword(&m);
1236 else
1237 #endif
1238 FinishAttach(&m);
1239 break;
1240 case MSG_ERROR:
1241 {
1242 int blocked=D_blocked;
1243 if(D_blocked == 4) /* allow error messages while in blanker mode */
1244 D_blocked=0; /* likely they're from failed blanker */
1245 Msg(0, "%s", m.m.message);
1246 D_blocked=blocked;
1247 }
1248 break;
1249 case MSG_HANGUP:
1250 if (!wi) /* ignore hangups from inside */
1251 Hangup();
1252 break;
1253 #ifdef REMOTE_DETACH
1254 case MSG_DETACH:
1255 #ifdef POW_DETACH
1256 case MSG_POW_DETACH:
1257 #endif /* POW_DETACH */
1258 #ifdef PASSWORD
1259 user = *FindUserPtr(m.m.detach.duser);
1260 if (user && user->u_password && *user->u_password)
1261 {
1262 if (CreateTempDisplay(&m, recvfd, 0))
1263 break;
1264 AskPassword(&m);
1265 }
1266 else
1267 #endif /* PASSWORD */
1268 FinishDetach(&m);
1269 break;
1270 #endif
1271 case MSG_QUERY:
1272 {
1273 char *oldSockPath = SaveStr(SockPath);
1274 strcpy(SockPath, m.m.command.writeback);
1275 bool is_socket = IsSocket(SockPath);
1276 int s = MakeClientSocket(0, is_socket);
1277 strcpy(SockPath, oldSockPath);
1278 Free(oldSockPath);
1279 if (s >= 0)
1280 {
1281 queryflag = s;
1282 DoCommandMsg(&m);
1283 close(s);
1284 }
1285 else
1286 queryflag = -1;
1287
1288 Kill(m.m.command.apid,
1289 (queryflag >= 0)
1290 ? SIGCONT
1291 : SIG_BYE); /* Send SIG_BYE if an error happened */
1292 queryflag = -1;
1293 }
1294 break;
1295 case MSG_COMMAND:
1296 DoCommandMsg(&m);
1297 break;
1298 default:
1299 Msg(0, "Invalid message (type %d).", m.type);
1300 }
1301 }
1302
1303 void
ReceiveRaw(s)1304 ReceiveRaw(s)
1305 int s;
1306 {
1307 char rd[256];
1308 int len = 0;
1309 struct sockaddr_un a;
1310 bool is_socket;
1311
1312 is_socket = IsSocket(SockPath);
1313 if (!is_socket)
1314 {
1315 if (fcntl(s, F_SETFL, 0) < 0)
1316 Panic(errno, "BLOCK fcntl");
1317 }
1318 else
1319 {
1320 len = sizeof(a);
1321 s = accept(s, (struct sockaddr *)&a, (void *)&len);
1322 if (s < 0)
1323 {
1324 Msg(errno, "accept");
1325 return;
1326 }
1327 }
1328
1329 while ((len = read(s, rd, 255)) > 0)
1330 {
1331 rd[len] = 0;
1332 printf("%s", rd);
1333 }
1334 close(s);
1335 }
1336
1337 #if defined(_SEQUENT_)
1338 #undef connect
1339 /*
1340 * sequent_ptx socket emulation must have mode 000 on the socket!
1341 */
1342 static int
sconnect(s,sapp,len)1343 sconnect(s, sapp, len)
1344 int s, len;
1345 struct sockaddr *sapp;
1346 {
1347 register struct sockaddr_un *sap;
1348 struct stat st;
1349 int x;
1350
1351 sap = (struct sockaddr_un *)sapp;
1352 if (stat(sap->sun_path, &st))
1353 return -1;
1354 chmod(sap->sun_path, 0);
1355 x = connect(s, (struct sockaddr *) sap, len);
1356 chmod(sap->sun_path, st.st_mode);
1357 return x;
1358 }
1359 #endif
1360
1361
1362 /*
1363 * Set the mode bits of the socket to the current status
1364 */
1365 int
chsock()1366 chsock()
1367 {
1368 int r, euid = geteuid();
1369 if (euid != real_uid)
1370 {
1371 if (UserContext() <= 0)
1372 return UserStatus();
1373 }
1374 r = chmod(SockPath, SOCKMODE);
1375 /*
1376 * Sockets usually reside in the /tmp/ area, where sysadmin scripts
1377 * may be happy to remove old files. We manually prevent the socket
1378 * from becoming old. (chmod does not touch mtime).
1379 */
1380 (void)utimes(SockPath, NULL);
1381
1382 if (euid != real_uid)
1383 UserReturn(r);
1384 return r;
1385 }
1386
1387 /*
1388 * Try to recreate the socket/pipe
1389 */
1390 int
RecoverSocket()1391 RecoverSocket()
1392 {
1393 bool is_socket;
1394
1395 close(ServerSocket);
1396 if ((int)geteuid() != real_uid)
1397 {
1398 if (UserContext() > 0)
1399 UserReturn(unlink(SockPath));
1400 (void)UserStatus();
1401 }
1402 else
1403 (void) unlink(SockPath);
1404
1405 is_socket = IsSocket(SockPath);
1406 if ((ServerSocket = MakeServerSocket(is_socket)) < 0)
1407 return 0;
1408 evdeq(&serv_read);
1409 serv_read.fd = ServerSocket;
1410 evenq(&serv_read);
1411 return 1;
1412 }
1413
1414
1415 static void
FinishAttach(m)1416 FinishAttach(m)
1417 struct msg *m;
1418 {
1419 char *p;
1420 int pid;
1421 int noshowwin;
1422 struct win *wi;
1423
1424 ASSERT(display);
1425 pid = D_userpid;
1426
1427 #ifdef REMOTE_DETACH
1428 if (m->m.attach.detachfirst == MSG_DETACH
1429 # ifdef POW_DETACH
1430 || m->m.attach.detachfirst == MSG_POW_DETACH
1431 # endif
1432 )
1433 FinishDetach(m);
1434 #endif
1435
1436 #if defined(pyr) || defined(xelos) || defined(sequent)
1437 /*
1438 * Kludge for systems with braindamaged termcap routines,
1439 * which evaluate $TERMCAP, regardless whether it describes
1440 * the correct terminal type or not.
1441 */
1442 debug("unsetenv(TERMCAP) in case of a different terminal");
1443 unsetenv("TERMCAP");
1444 #endif
1445
1446 /*
1447 * We reboot our Terminal Emulator. Forget all we knew about
1448 * the old terminal, reread the termcap entries in .screenrc
1449 * (and nothing more from .screenrc is read. Mainly because
1450 * I did not check, whether a full reinit is safe. jw)
1451 * and /etc/screenrc, and initialise anew.
1452 */
1453 if (extra_outcap)
1454 free(extra_outcap);
1455 if (extra_incap)
1456 free(extra_incap);
1457 extra_incap = extra_outcap = 0;
1458 debug2("Message says size (%dx%d)\n", m->m.attach.columns, m->m.attach.lines);
1459 #ifdef ETCSCREENRC
1460 # ifdef ALLOW_SYSSCREENRC
1461 if ((p = getenv("SYSSCREENRC")))
1462 StartRc(p, 1);
1463 else
1464 # endif
1465 StartRc(ETCSCREENRC, 1);
1466 #endif
1467 StartRc(RcFileName, 1);
1468 if (InitTermcap(m->m.attach.columns, m->m.attach.lines))
1469 {
1470 FreeDisplay();
1471 Kill(pid, SIG_BYE);
1472 return;
1473 }
1474 MakeDefaultCanvas();
1475 InitTerm(m->m.attach.adaptflag); /* write init string on fd */
1476 if (displays->d_next == 0)
1477 (void) chsock();
1478 signal(SIGHUP, SigHup);
1479 if (m->m.attach.esc != -1 && m->m.attach.meta_esc != -1)
1480 {
1481 D_user->u_Esc = m->m.attach.esc;
1482 D_user->u_MetaEsc = m->m.attach.meta_esc;
1483 }
1484
1485 #ifdef UTMPOK
1486 /*
1487 * we set the Utmp slots again, if we were detached normally
1488 * and if we were detached by ^Z.
1489 * don't log zomies back in!
1490 */
1491 RemoveLoginSlot();
1492 if (displays->d_next == 0)
1493 for (wi = windows; wi; wi = wi->w_next)
1494 if (wi->w_ptyfd >= 0 && wi->w_slot != (slot_t) -1)
1495 SetUtmp(wi);
1496 #endif
1497
1498 D_fore = NULL;
1499 if (layout_attach)
1500 {
1501 struct layout *lay = layout_attach;
1502 if (lay == &layout_last_marker)
1503 lay = layout_last;
1504 if (lay)
1505 {
1506 LoadLayout(lay, &D_canvas);
1507 SetCanvasWindow(D_forecv, 0);
1508 }
1509 }
1510 /*
1511 * there may be a window that we remember from last detach:
1512 */
1513 debug1("D_user->u_detachwin = %d\n", D_user->u_detachwin);
1514 if (D_user->u_detachwin >= 0)
1515 fore = wtab[D_user->u_detachwin];
1516 else
1517 fore = 0;
1518
1519 /* Wayne wants us to restore the other window too. */
1520 if (D_user->u_detachotherwin >= 0)
1521 D_other = wtab[D_user->u_detachotherwin];
1522
1523 noshowwin = 0;
1524 if (*m->m.attach.preselect)
1525 {
1526 if (!strcmp(m->m.attach.preselect, "="))
1527 fore = 0;
1528 else if (!strcmp(m->m.attach.preselect, "-"))
1529 {
1530 fore = 0;
1531 noshowwin = 1;
1532 }
1533 else if (!strcmp(m->m.attach.preselect, "+"))
1534 {
1535 struct action newscreen;
1536 char *na = 0;
1537 newscreen.nr = RC_SCREEN;
1538 newscreen.args = &na;
1539 newscreen.quiet = 0;
1540 DoAction(&newscreen, -1);
1541 }
1542 else
1543 fore = FindNiceWindow(fore, m->m.attach.preselect);
1544 }
1545 else
1546 fore = FindNiceWindow(fore, 0);
1547 if (fore)
1548 SetForeWindow(fore);
1549 else if (!noshowwin)
1550 {
1551 #ifdef MULTIUSER
1552 if (!AclCheckPermCmd(D_user, ACL_EXEC, &comms[RC_WINDOWLIST]))
1553 #endif
1554 {
1555 struct display *olddisplay = display;
1556 flayer = D_forecv->c_layer;
1557 display_windows(1, WLIST_NUM, (struct win *)0);
1558 noshowwin = 1;
1559 display = olddisplay; /* display_windows can change display */
1560 }
1561 }
1562 Activate(0);
1563 ResetIdle();
1564 if (!D_fore && !noshowwin)
1565 ShowWindows(-1);
1566 if (displays->d_next == 0 && console_window)
1567 {
1568 if (TtyGrabConsole(console_window->w_ptyfd, 1, "reattach") == 0)
1569 Msg(0, "console %s is on window %d", HostName, console_window->w_number);
1570 }
1571 debug("activated...\n");
1572
1573 # if defined(DEBUG) && defined(SIG_NODEBUG)
1574 if (!dfp)
1575 {
1576 sleep(1);
1577 debug1("Attacher %d must not debug, as we have debug off.\n", pid);
1578 kill(pid, SIG_NODEBUG);
1579 }
1580 # endif /* SIG_NODEBUG */
1581 }
1582
1583 static void
FinishDetach(m)1584 FinishDetach(m)
1585 struct msg *m;
1586 {
1587 struct display *next, **d, *det;
1588 int pid;
1589
1590 if (m->type == MSG_ATTACH)
1591 pid = D_userpid;
1592 else
1593 pid = m->m.detach.dpid;
1594
1595 /* Remove the temporary display prompting for the password from the list */
1596 for (d = &displays; (det = *d); d = &det->d_next)
1597 {
1598 if (det->d_userpid == pid)
1599 break;
1600 }
1601 if (det)
1602 {
1603 *d = det->d_next;
1604 det->d_next = 0;
1605 }
1606
1607 for (display = displays; display; display = next)
1608 {
1609 next = display->d_next;
1610 # ifdef POW_DETACH
1611 if (m->type == MSG_POW_DETACH)
1612 Detach(D_REMOTE_POWER);
1613 else
1614 # endif /* POW_DETACH */
1615 if (m->type == MSG_DETACH)
1616 Detach(D_REMOTE);
1617 else if (m->type == MSG_ATTACH)
1618 {
1619 #ifdef POW_DETACH
1620 if (m->m.attach.detachfirst == MSG_POW_DETACH)
1621 Detach(D_REMOTE_POWER);
1622 else
1623 #endif
1624 if (m->m.attach.detachfirst == MSG_DETACH)
1625 Detach(D_REMOTE);
1626 }
1627 }
1628 display = displays = det;
1629 if (m->type != MSG_ATTACH)
1630 {
1631 if (display)
1632 FreeDisplay();
1633 Kill(pid, SIGCONT);
1634 }
1635 }
1636
1637 #ifdef PASSWORD
1638 static void PasswordProcessInput __P((char *, int));
1639
1640 struct pwdata {
1641 int l;
1642 char buf[MAXLOGINLEN + 1];
1643 struct msg m;
1644 };
1645
1646 static void
AskPassword(m)1647 AskPassword(m)
1648 struct msg *m;
1649 {
1650 struct pwdata *pwdata;
1651 ASSERT(display);
1652 pwdata = (struct pwdata *)malloc(sizeof(struct pwdata));
1653 if (!pwdata)
1654 Panic(0, "%s", strnomem);
1655 pwdata->l = 0;
1656 pwdata->m = *m;
1657 D_processinputdata = (char *)pwdata;
1658 D_processinput = PasswordProcessInput;
1659 AddStr("Screen password: ");
1660 }
1661
1662 static void
PasswordProcessInput(ibuf,ilen)1663 PasswordProcessInput(ibuf, ilen)
1664 char *ibuf;
1665 int ilen;
1666 {
1667 struct pwdata *pwdata;
1668 int c, l;
1669 char *up;
1670 int pid = D_userpid;
1671
1672 pwdata = (struct pwdata *)D_processinputdata;
1673 l = pwdata->l;
1674 while (ilen-- > 0)
1675 {
1676 c = *(unsigned char *)ibuf++;
1677 if (c == '\r' || c == '\n')
1678 {
1679 char *buf = NULL;
1680 up = D_user->u_password;
1681 pwdata->buf[l] = 0;
1682 buf = crypt(pwdata->buf, up);
1683 if (!buf || strncmp(buf, up, strlen(up)))
1684 {
1685 /* uh oh, user failed */
1686 bzero(pwdata->buf, sizeof(pwdata->buf));
1687 if (!buf)
1688 AddStr("\r\ncrypt() failed.\r\n");
1689 else
1690 AddStr("\r\nPassword incorrect.\r\n");
1691 D_processinputdata = 0; /* otherwise freed by FreeDis */
1692 FreeDisplay();
1693 Msg(0, "Illegal reattach attempt from terminal %s.", pwdata->m.m_tty);
1694 free(pwdata);
1695 Kill(pid, SIG_BYE);
1696 return;
1697 }
1698 /* great, pw matched, all is fine */
1699 bzero(pwdata->buf, sizeof(pwdata->buf));
1700 AddStr("\r\n");
1701 D_processinputdata = 0;
1702 D_processinput = ProcessInput;
1703 #ifdef REMOTE_DETACH
1704 if (pwdata->m.type == MSG_DETACH
1705 # ifdef POW_DETACH
1706 || pwdata->m.type == MSG_POW_DETACH
1707 # endif
1708 )
1709 FinishDetach(&pwdata->m);
1710 else
1711 #endif
1712 FinishAttach(&pwdata->m);
1713 free(pwdata);
1714 return;
1715 }
1716 if (c == Ctrl('c'))
1717 {
1718 AddStr("\r\n");
1719 FreeDisplay();
1720 Kill(pid, SIG_BYE);
1721 return;
1722 }
1723 if (c == '\b' || c == 0177)
1724 {
1725 if (l > 0)
1726 l--;
1727 continue;
1728 }
1729 if (c == Ctrl('u'))
1730 {
1731 l = 0;
1732 continue;
1733 }
1734 if (l < (int)sizeof(pwdata->buf) - 1)
1735 pwdata->buf[l++] = c;
1736 }
1737 pwdata->l = l;
1738 }
1739 #endif
1740
1741 /* 'end' is exclusive, i.e. you should *not* write in *end */
1742 static char *
strncpy_escape_quote(dst,src,end)1743 strncpy_escape_quote(dst, src, end)
1744 char *dst;
1745 const char *src, *end;
1746 {
1747 while (*src && dst < end)
1748 {
1749 if (*src == '"')
1750 {
1751 if (dst + 2 < end) /* \\ \" \0 */
1752 *dst++ = '\\';
1753 else
1754 return NULL;
1755 }
1756 *dst++ = *src++;
1757 }
1758 if (dst >= end)
1759 return NULL;
1760
1761 *dst = '\0';
1762 return dst;
1763 }
1764
1765 static void
DoCommandMsg(mp)1766 DoCommandMsg(mp)
1767 struct msg *mp;
1768 {
1769 char *args[MAXARGS];
1770 int argl[MAXARGS];
1771 char fullcmd[MAXSTR];
1772 register char *fc;
1773 int n;
1774 register char *p = mp->m.command.cmd;
1775 struct acluser *user;
1776 #ifdef MULTIUSER
1777 extern struct acluser *EffectiveAclUser; /* acls.c */
1778 #else
1779 extern struct acluser *users; /* acls.c */
1780 #endif
1781
1782 n = mp->m.command.nargs;
1783 if (n > MAXARGS - 1)
1784 n = MAXARGS - 1;
1785 for (fc = fullcmd; n > 0; n--)
1786 {
1787 int len = strlen(p);
1788 *fc++ = '"';
1789 if (!(fc = strncpy_escape_quote(fc, p, fullcmd + sizeof(fullcmd) - 2))) /* '"' ' ' */
1790 {
1791 Msg(0, "Remote command too long.");
1792 queryflag = -1;
1793 return;
1794 }
1795 p += len + 1;
1796 *fc++ = '"';
1797 *fc++ = ' ';
1798 }
1799 if (fc != fullcmd)
1800 *--fc = 0;
1801 if (Parse(fullcmd, sizeof fullcmd, args, argl) <= 0)
1802 {
1803 queryflag = -1;
1804 return;
1805 }
1806 #ifdef MULTIUSER
1807 user = *FindUserPtr(mp->m.attach.auser);
1808 if (user == 0)
1809 {
1810 Msg(0, "Unknown user %s tried to send a command!", mp->m.attach.auser);
1811 queryflag = -1;
1812 return;
1813 }
1814 #else
1815 user = users;
1816 #endif
1817 #ifdef PASSWORD
1818 if (user->u_password && *user->u_password)
1819 {
1820 Msg(0, "User %s has a password, cannot use remote commands (using -Q or -X option).", mp->m.attach.auser);
1821 queryflag = -1;
1822 return;
1823 }
1824 #endif
1825 if (!display)
1826 for (display = displays; display; display = display->d_next)
1827 if (D_user == user)
1828 break;
1829 for (fore = windows; fore; fore = fore->w_next)
1830 if (!TTYCMP(mp->m_tty, fore->w_tty))
1831 {
1832 if (!display)
1833 display = fore->w_layer.l_cvlist ? fore->w_layer.l_cvlist->c_display : 0;
1834
1835 /* If the window is not visibile in any display, then do not use the originating window as
1836 * the foreground window for the command. This way, if there is an existing display, then
1837 * the command will execute from the foreground window of that display. This is necessary so
1838 * that commands that are relative to the window (e.g. 'next' etc.) do the right thing. */
1839 if (!fore->w_layer.l_cvlist || !fore->w_layer.l_cvlist->c_display)
1840 fore = NULL;
1841 break;
1842 }
1843 if (!display)
1844 display = displays; /* sigh */
1845 if (*mp->m.command.preselect)
1846 {
1847 int i = -1;
1848 if (strcmp(mp->m.command.preselect, "-"))
1849 {
1850 i = WindowByNoN(mp->m.command.preselect);
1851 if (i < 0 || !wtab[i])
1852 {
1853 Msg(0, "Could not find pre-select window.");
1854 queryflag = -1;
1855 return;
1856 }
1857 }
1858 fore = i >= 0 ? wtab[i] : 0;
1859 }
1860 else if (!fore)
1861 {
1862 if (display && D_user == user)
1863 fore = Layer2Window(display->d_forecv->c_layer);
1864 if (!fore)
1865 {
1866 fore = user->u_detachwin >= 0 ? wtab[user->u_detachwin] : 0;
1867 fore = FindNiceWindow(fore, 0);
1868 }
1869 }
1870 if (!fore)
1871 fore = windows; /* sigh */
1872 #ifdef MULTIUSER
1873 EffectiveAclUser = user;
1874 #endif
1875 if (*args)
1876 {
1877 char *oldrcname = rc_name;
1878 rc_name = "-X";
1879 debug3("Running command on display %x window %x (%d)\n", display, fore, fore ? fore->w_number : -1);
1880 flayer = fore ? &fore->w_layer : 0;
1881 if (fore && fore->w_savelayer && (fore->w_blocked || fore->w_savelayer->l_cvlist == 0))
1882 flayer = fore->w_savelayer;
1883 DoCommand(args, argl);
1884 rc_name = oldrcname;
1885 }
1886 #ifdef MULTIUSER
1887 EffectiveAclUser = 0;
1888 #endif
1889 }
1890
1891 int
SendAttachMsg(s,m,fd)1892 SendAttachMsg(s, m, fd)
1893 int s;
1894 struct msg *m;
1895 int fd;
1896 {
1897 int r;
1898 struct msghdr msg;
1899 struct iovec iov;
1900 char buf[CMSG_SPACE(sizeof(int))];
1901 struct cmsghdr *cmsg;
1902
1903 iov.iov_base = (char *)m;
1904 iov.iov_len = sizeof(*m);
1905 bzero(&msg, sizeof(msg));
1906 msg.msg_name = 0;
1907 msg.msg_namelen = 0;
1908 msg.msg_iov = &iov;
1909 msg.msg_iovlen = 1;
1910 msg.msg_control = buf;
1911 msg.msg_controllen = sizeof(buf);
1912 cmsg = CMSG_FIRSTHDR(&msg);
1913 cmsg->cmsg_level = SOL_SOCKET;
1914 cmsg->cmsg_type = SCM_RIGHTS;
1915 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
1916 bcopy(&fd, CMSG_DATA(cmsg), sizeof(int));
1917 msg.msg_controllen = cmsg->cmsg_len;
1918 while(1)
1919 {
1920 r = sendmsg(s, &msg, 0);
1921 if (r == -1 && errno == EINTR)
1922 continue;
1923 if (r == -1)
1924 return -1;
1925 return 0;
1926 }
1927 }
1928
1929 bool
IsSocket(path)1930 IsSocket(path)
1931 const char *path;
1932 {
1933 struct stat st;
1934
1935 if (stat(path, &st) < 0)
1936 return false;
1937
1938 return S_ISSOCK(st.st_mode);
1939 }
1940