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