1/* Copyright (c) 1993-2002
2 *      Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 *      Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Copyright (c) 1987 Oliver Laumann
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program (see the file COPYING); if not, write to the
18 * Free Software Foundation, Inc.,
19 * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
20 *
21 ****************************************************************
22 */
23
24#include "config.h"
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <fcntl.h>
28#if !defined(NAMEDPIPE)
29#include <sys/socket.h>
30#include <sys/un.h>
31#endif
32
33#ifndef SIGINT
34# include <signal.h>
35#endif
36
37#include "screen.h"
38
39#ifdef HAVE_DIRENT_H
40# include <dirent.h>
41#else
42# include <sys/dir.h>
43# define dirent direct
44#endif
45
46#include "extern.h"
47
48static int   CheckPid __P((int));
49static void  ExecCreate __P((struct msg *));
50static void  DoCommandMsg __P((struct msg *));
51#if defined(_SEQUENT_) && !defined(NAMEDPIPE)
52# define connect sconnect	/* _SEQUENT_ has braindamaged connect */
53static int   sconnect __P((int, struct sockaddr *, int));
54#endif
55static void  FinishAttach __P((struct msg *));
56static void  AskPassword __P((struct msg *));
57
58
59extern char *RcFileName, *extra_incap, *extra_outcap;
60extern int ServerSocket, real_uid, real_gid, eff_uid, eff_gid;
61extern int dflag, iflag, rflag, lsflag, quietflag, wipeflag, xflag;
62extern char *attach_tty, *LoginName, HostName[];
63extern struct display *display, *displays;
64extern struct win *fore, *wtab[], *console_window, *windows;
65extern struct layer *flayer;
66extern struct NewWindow nwin_undef;
67#ifdef MULTIUSER
68extern char *multi;
69#endif
70
71extern char *getenv();
72
73extern char SockPath[];
74extern struct event serv_read;
75extern char *rc_name;
76extern struct comm comms[];
77
78#ifdef MULTIUSER
79# define SOCKMODE (S_IWRITE | S_IREAD | (displays ? S_IEXEC : 0) | (multi ? 1 : 0))
80#else
81# define SOCKMODE (S_IWRITE | S_IREAD | (displays ? S_IEXEC : 0))
82#endif
83
84
85/*
86 *  Socket directory manager
87 *
88 *  fdp: pointer to store the first good socket.
89 *  nfoundp: pointer to store the number of sockets found matching.
90 *  notherp: pointer to store the number of sockets not matching.
91 *  match: string to match socket name.
92 *
93 *  The socket directory must be in SockPath!
94 *  The global variables LoginName, multi, rflag, xflag, dflag,
95 *  quietflag, SockPath are used.
96 *
97 *  The first good socket is stored in fdp and its name is
98 *  appended to SockPath.
99 *  If none exists or fdp is NULL SockPath is not changed.
100 *
101 *  Returns: number of good sockets.
102 *
103 */
104
105int
106FindSocket(fdp, nfoundp, notherp, match)
107int *fdp;
108int *nfoundp, *notherp;
109char *match;
110{
111  DIR *dirp;
112  struct dirent *dp;
113  struct stat st;
114  int mode;
115  int sdirlen;
116  int  matchlen = 0;
117  char *name, *n;
118  int firsts = -1, sockfd;
119  char *firstn = NULL;
120  int nfound = 0, ngood = 0, ndead = 0, nwipe = 0, npriv = 0;
121  struct sent
122    {
123      struct sent *next;
124      int mode;
125      char *name;
126    } *slist, **slisttail, *sent, *nsent;
127
128  if (match)
129    {
130      matchlen = strlen(match);
131#ifdef NAME_MAX
132      if (matchlen > NAME_MAX)
133	matchlen = NAME_MAX;
134#endif
135    }
136
137  /*
138   * SockPath contains the socket directory.
139   * At the end of FindSocket the socket name will be appended to it.
140   * Thus FindSocket() can only be called once!
141   */
142  sdirlen = strlen(SockPath);
143
144#ifdef USE_SETEUID
145  xseteuid(real_uid);
146  xsetegid(real_gid);
147#endif
148
149  if ((dirp = opendir(SockPath)) == 0)
150    Panic(errno, "Cannot opendir %s", SockPath);
151
152  slist = 0;
153  slisttail = &slist;
154  while ((dp = readdir(dirp)))
155    {
156      name = dp->d_name;
157      debug1("- %s\n",  name);
158      if (*name == 0 || *name == '.' || strlen(name) > 2*MAXSTR)
159	continue;
160      if (matchlen)
161	{
162	  n = name;
163	  /* if we don't want to match digits. Skip them */
164	  if ((*match <= '0' || *match > '9') && (*n > '0' && *n <= '9'))
165	    {
166	      while (*n >= '0' && *n <= '9')
167		n++;
168	      if (*n == '.')
169		n++;
170	    }
171	  /* the tty prefix is optional */
172	  if (strncmp(match, "tty", 3) && strncmp(n, "tty", 3) == 0)
173	    n += 3;
174	  if (strncmp(match, n, matchlen))
175	    continue;
176	  debug1("  -> matched %s\n", match);
177	}
178      sprintf(SockPath + sdirlen, "/%s", name);
179
180      debug1("stat %s\n", SockPath);
181      errno = 0;
182      debug2("uid = %d, gid = %d\n", getuid(), getgid());
183      debug2("euid = %d, egid = %d\n", geteuid(), getegid());
184      if (stat(SockPath, &st))
185	{
186	  debug1("errno = %d\n", errno);
187	  continue;
188	}
189
190#ifndef SOCK_NOT_IN_FS
191# ifdef NAMEDPIPE
192#  ifdef S_ISFIFO
193      debug("S_ISFIFO?\n");
194      if (!S_ISFIFO(st.st_mode))
195	continue;
196#  endif
197# else
198#  ifdef S_ISSOCK
199      debug("S_ISSOCK?\n");
200      if (!S_ISSOCK(st.st_mode))
201	continue;
202#  endif
203# endif
204#endif
205
206      debug2("st.st_uid = %d, real_uid = %d\n", st.st_uid, real_uid);
207      if ((int)st.st_uid != real_uid)
208	continue;
209      mode = (int)st.st_mode & 0777;
210      debug1("  has mode 0%03o\n", mode);
211#ifdef MULTIUSER
212      if (multi && ((mode & 0677) != 0601))
213        {
214	  debug("  is not a MULTI-USER session");
215	  if (strcmp(multi, LoginName))
216	    {
217	      debug(" and we are in a foreign directory.\n");
218	      mode = -4;
219	    }
220	  else
221	    {
222	      debug(", but it is our own session.\n");
223	    }
224	}
225#endif
226      debug("  store it.\n");
227      if ((sent = (struct sent *)malloc(sizeof(struct sent))) == 0)
228	continue;
229      sent->next = 0;
230      sent->name = SaveStr(name);
231      sent->mode = mode;
232      *slisttail = sent;
233      slisttail = &sent->next;
234      nfound++;
235      sockfd = MakeClientSocket(0);
236#ifdef USE_SETEUID
237      /* MakeClientSocket sets ids back to eff */
238      xseteuid(real_uid);
239      xsetegid(real_gid);
240#endif
241      if (sockfd == -1)
242	{
243	  debug2("  MakeClientSocket failed, unreachable? %d %d\n",
244	         matchlen, wipeflag);
245	  sent->mode = -3;
246#ifndef SOCKDIR_IS_LOCAL_TO_HOST
247	  /* Unreachable - it is dead if we detect that it's local
248           * or we specified a match
249           */
250	  n = name + strlen(name) - 1;
251	  while (n != name && *n != '.')
252	    n--;
253	  if (matchlen == 0  && !(*n == '.' && n[1] && strncmp(HostName, n + 1, strlen(n + 1)) == 0))
254	    {
255	      npriv++;		/* a good socket that was not for us */
256	      continue;
257	    }
258#endif
259	  ndead++;
260	  sent->mode = -1;
261	  if (wipeflag)
262	    {
263	      if (unlink(SockPath) == 0)
264		{
265		  sent->mode = -2;
266		  nwipe++;
267		}
268	    }
269	  continue;
270	}
271
272      mode &= 0776;
273      /* Shall we connect ? */
274      debug2("  connecting: mode=%03o, rflag=%d, ", mode, rflag);
275      debug2("xflag=%d, dflag=%d ?\n", xflag, dflag);
276
277      /*
278       * mode 600: socket is detached.
279       * mode 700: socket is attached.
280       * xflag implies rflag here.
281       *
282       * fail, when socket mode mode is not 600 or 700
283       * fail, when we want to detach w/o reattach, but it already is detached.
284       * fail, when we only want to attach, but mode 700 and not xflag.
285       * fail, if none of dflag, rflag, xflag is set.
286       */
287      if ((mode != 0700 && mode != 0600) ||
288          (dflag && !rflag && !xflag && mode == 0600) ||
289	  (!dflag && rflag && mode == 0700 && !xflag) ||
290	  (!dflag && !rflag && !xflag))
291	{
292	  close(sockfd);
293	  debug("  no!\n");
294	  npriv++;		/* a good socket that was not for us */
295	  continue;
296	}
297      ngood++;
298      if (fdp && firsts == -1)
299	{
300	  firsts = sockfd;
301	  firstn = sent->name;
302	  debug("  taken.\n");
303	}
304      else
305        {
306	  debug("  discarded.\n");
307	  close(sockfd);
308	}
309    }
310  (void)closedir(dirp);
311  if (nfound && (lsflag || ngood != 1) && !quietflag)
312    {
313      switch(ngood)
314	{
315	case 0:
316	  Msg(0, nfound > 1 ? "There are screens on:" : "There is a screen on:");
317	  break;
318	case 1:
319	  Msg(0, nfound > 1 ? "There are several screens on:" : "There is a suitable screen on:");
320	  break;
321	default:
322	  Msg(0, "There are several suitable screens on:");
323	  break;
324	}
325      for (sent = slist; sent; sent = sent->next)
326	{
327	  switch (sent->mode)
328	    {
329	    case 0700:
330	      printf("\t%s\t(Attached)\n", sent->name);
331	      break;
332	    case 0600:
333	      printf("\t%s\t(Detached)\n", sent->name);
334	      break;
335#ifdef MULTIUSER
336	    case 0701:
337	      printf("\t%s\t(Multi, attached)\n", sent->name);
338	      break;
339	    case 0601:
340	      printf("\t%s\t(Multi, detached)\n", sent->name);
341	      break;
342#endif
343	    case -1:
344	      /* No trigraphs here! */
345	      printf("\t%s\t(Dead ?%c?)\n", sent->name, '?');
346	      break;
347	    case -2:
348	      printf("\t%s\t(Removed)\n", sent->name);
349	      break;
350	    case -3:
351	      printf("\t%s\t(Remote or dead)\n", sent->name);
352	      break;
353	    case -4:
354	      printf("\t%s\t(Private)\n", sent->name);
355	      break;
356	    }
357	}
358    }
359  if (ndead && !quietflag)
360    {
361      char *m = "Remove dead screens with 'screen -wipe'.";
362      if (wipeflag)
363        Msg(0, "%d socket%s wiped out.", nwipe, nwipe > 1 ? "s" : "");
364      else
365        Msg(0, m, ndead > 1 ? "s" : "", ndead > 1 ? "" : "es");	/* other args for nethack */
366    }
367  if (firsts != -1)
368    {
369      sprintf(SockPath + sdirlen, "/%s", firstn);
370      *fdp = firsts;
371    }
372  else
373    SockPath[sdirlen] = 0;
374  for (sent = slist; sent; sent = nsent)
375    {
376      nsent = sent->next;
377      free(sent->name);
378      free((char *)sent);
379    }
380#ifdef USE_SETEUID
381  xseteuid(eff_uid);
382  xsetegid(eff_gid);
383#endif
384  if (notherp)
385    *notherp = npriv;
386  if (nfoundp)
387    *nfoundp = nfound - nwipe;
388  return ngood;
389}
390
391
392/*
393**
394**        Socket/pipe create routines
395**
396*/
397
398#ifdef NAMEDPIPE
399
400int
401MakeServerSocket()
402{
403  register int s;
404  struct stat st;
405
406# ifdef USE_SETEUID
407  xseteuid(real_uid);
408  xsetegid(real_gid);
409# endif
410  if ((s = open(SockPath, O_WRONLY | O_NONBLOCK)) >= 0)
411    {
412      debug("huii, my fifo already exists??\n");
413      if (quietflag)
414	{
415	  Kill(D_userpid, SIG_BYE);
416	  eexit(11);
417	}
418      Msg(0, "There is already a screen running on %s.", Filename(SockPath));
419      if (stat(SockPath, &st) == -1)
420	Panic(errno, "stat");
421      if ((int)st.st_uid != real_uid)
422	Panic(0, "Unfortunatelly you are not its owner.");
423      if ((st.st_mode & 0700) == 0600)
424	Panic(0, "To resume it, use \"screen -r\"");
425      else
426	Panic(0, "It is not detached.");
427      /* NOTREACHED */
428    }
429# ifdef USE_SETEUID
430  (void) unlink(SockPath);
431  if (mkfifo(SockPath, SOCKMODE))
432    Panic(0, "mkfifo %s failed", SockPath);
433#  ifdef BROKEN_PIPE
434  if ((s = open(SockPath, O_RDWR | O_NONBLOCK, 0)) < 0)
435#  else
436  if ((s = open(SockPath, O_RDONLY | O_NONBLOCK, 0)) < 0)
437#  endif
438    Panic(errno, "open fifo %s", SockPath);
439  xseteuid(eff_uid);
440  xsetegid(eff_gid);
441  return s;
442# else /* !USE_SETEUID */
443  if (UserContext() > 0)
444    {
445      (void) unlink(SockPath);
446      UserReturn(mkfifo(SockPath, SOCKMODE));
447    }
448  if (UserStatus())
449    Panic(0, "mkfifo %s failed", SockPath);
450#  ifdef BROKEN_PIPE
451  if ((s = secopen(SockPath, O_RDWR | O_NONBLOCK, 0)) < 0)
452#  else
453  if ((s = secopen(SockPath, O_RDONLY | O_NONBLOCK, 0)) < 0)
454#  endif
455    Panic(errno, "open fifo %s", SockPath);
456  return s;
457# endif /* !USE_SETEUID */
458}
459
460
461int
462MakeClientSocket(err)
463int err;
464{
465  register int s = 0;
466
467  if ((s = secopen(SockPath, O_WRONLY | O_NONBLOCK, 0)) >= 0)
468    {
469      (void) fcntl(s, F_SETFL, 0);
470      return s;
471    }
472  if (err)
473    Msg(errno, "%s", SockPath);
474  debug2("MakeClientSocket() open %s failed (%d)\n", SockPath, errno);
475  return -1;
476}
477
478
479#else	/* NAMEDPIPE */
480
481
482int
483MakeServerSocket()
484{
485  register int s;
486  struct sockaddr_un a;
487  struct stat st;
488
489  if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
490    Panic(errno, "socket");
491  a.sun_family = AF_UNIX;
492  strncpy(a.sun_path, SockPath, sizeof(a.sun_path));
493  a.sun_path[sizeof(a.sun_path) - 1] = 0;
494# ifdef USE_SETEUID
495  xseteuid(real_uid);
496  xsetegid(real_gid);
497# endif
498  if (connect(s, (struct sockaddr *) &a, strlen(SockPath) + 2) != -1)
499    {
500      debug("oooooh! socket already is alive!\n");
501      if (quietflag)
502	{
503	  Kill(D_userpid, SIG_BYE);
504	  /*
505	   * oh, well. nobody receives that return code. papa
506	   * dies by signal.
507	   */
508	  eexit(11);
509	}
510      Msg(0, "There is already a screen running on %s.", Filename(SockPath));
511      if (stat(SockPath, &st) == -1)
512	Panic(errno, "stat");
513      if (st.st_uid != real_uid)
514	Panic(0, "Unfortunatelly you are not its owner.");
515      if ((st.st_mode & 0700) == 0600)
516	Panic(0, "To resume it, use \"screen -r\"");
517      else
518	Panic(0, "It is not detached.");
519      /* NOTREACHED */
520    }
521#if defined(m88k) || defined(sysV68)
522  close(s);	/* we get bind: Invalid argument if this is not done */
523  if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
524    Panic(errno, "reopen socket");
525#endif
526  (void) unlink(SockPath);
527  if (bind(s, (struct sockaddr *) & a, strlen(SockPath) + 2) == -1)
528    Panic(errno, "bind (%s)", SockPath);
529#ifdef SOCK_NOT_IN_FS
530    {
531      int f;
532      if ((f = secopen(SockPath, O_RDWR | O_CREAT, SOCKMODE)) < 0)
533        Panic(errno, "shadow socket open");
534      close(f);
535    }
536#else
537  chmod(SockPath, SOCKMODE);
538# ifndef USE_SETEUID
539  chown(SockPath, real_uid, real_gid);
540# endif
541#endif /* SOCK_NOT_IN_FS */
542  if (listen(s, 5) == -1)
543    Panic(errno, "listen");
544# ifdef F_SETOWN
545  fcntl(s, F_SETOWN, getpid());
546  debug1("Serversocket owned by %d\n", fcntl(s, F_GETOWN, 0));
547# endif /* F_SETOWN */
548# ifdef USE_SETEUID
549  xseteuid(eff_uid);
550  xsetegid(eff_gid);
551# endif
552  return s;
553}
554
555int
556MakeClientSocket(err)
557int err;
558{
559  register int s;
560  struct sockaddr_un a;
561
562  if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
563    Panic(errno, "socket");
564  a.sun_family = AF_UNIX;
565  strncpy(a.sun_path, SockPath, sizeof(a.sun_path));
566  a.sun_path[sizeof(a.sun_path) - 1] = 0;
567# ifdef USE_SETEUID
568  xseteuid(real_uid);
569  xsetegid(real_gid);
570# else
571  if (access(SockPath, W_OK))
572    {
573      if (err)
574	Msg(errno, "%s", SockPath);
575      debug2("MakeClientSocket: access(%s): %d.\n", SockPath, errno);
576      close(s);
577      return -1;
578    }
579# endif
580  if (connect(s, (struct sockaddr *) &a, strlen(SockPath) + 2) == -1)
581    {
582      if (err)
583	Msg(errno, "%s: connect", SockPath);
584      debug("MakeClientSocket: connect failed.\n");
585      close(s);
586      s = -1;
587    }
588# ifdef USE_SETEUID
589  xseteuid(eff_uid);
590  xsetegid(eff_gid);
591# endif
592  return s;
593}
594#endif /* NAMEDPIPE */
595
596
597/*
598**
599**       Message send and receive routines
600**
601*/
602
603void
604SendCreateMsg(sty, nwin)
605char *sty;
606struct NewWindow *nwin;
607{
608  int s;
609  struct msg m;
610  register char *p;
611  register int len, n;
612  char **av = nwin->args;
613
614#ifdef NAME_MAX
615  if (strlen(sty) > NAME_MAX)
616    sty[NAME_MAX] = 0;
617#endif
618  if (strlen(sty) > 2 * MAXSTR - 1)
619    sty[2 * MAXSTR - 1] = 0;
620  sprintf(SockPath + strlen(SockPath), "/%s", sty);
621  if ((s = MakeClientSocket(1)) == -1)
622    exit(1);
623  debug1("SendCreateMsg() to '%s'\n", SockPath);
624  bzero((char *)&m, sizeof(m));
625  m.type = MSG_CREATE;
626  strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1);
627  m.m_tty[sizeof(m.m_tty) - 1] = 0;
628  p = m.m.create.line;
629  n = 0;
630  if (nwin->args != nwin_undef.args)
631    for (av = nwin->args; *av && n < MAXARGS - 1; ++av, ++n)
632      {
633        len = strlen(*av) + 1;
634        if (p + len >= m.m.create.line + sizeof(m.m.create.line) - 1)
635	  break;
636        strcpy(p, *av);
637        p += len;
638      }
639  if (nwin->aka != nwin_undef.aka && p + strlen(nwin->aka) + 1 < m.m.create.line + sizeof(m.m.create.line))
640    strcpy(p, nwin->aka);
641  else
642    *p = '\0';
643  m.m.create.nargs = n;
644  m.m.create.aflag = nwin->aflag;
645  m.m.create.flowflag = nwin->flowflag;
646  m.m.create.lflag = nwin->lflag;
647  m.m.create.hheight = nwin->histheight;
648  if (getcwd(m.m.create.dir, sizeof(m.m.create.dir)) == 0)
649    {
650      Msg(errno, "getcwd");
651      return;
652    }
653  if (nwin->term != nwin_undef.term)
654    strncpy(m.m.create.screenterm, nwin->term, 19);
655  m.m.create.screenterm[19] = '\0';
656  m.protocol_revision = MSG_REVISION;
657  debug1("SendCreateMsg writing '%s'\n", m.m.create.line);
658  if (write(s, (char *) &m, sizeof m) != sizeof m)
659    Msg(errno, "write");
660  close(s);
661}
662
663int
664SendErrorMsg(tty, buf)
665char *tty, *buf;
666{
667  int s;
668  struct msg m;
669
670  strncpy(m.m.message, buf, sizeof(m.m.message) - 1);
671  m.m.message[sizeof(m.m.message) - 1] = 0;
672  s = MakeClientSocket(0);
673  if (s < 0)
674    return -1;
675  m.type = MSG_ERROR;
676  strncpy(m.m_tty, tty, sizeof(m.m_tty) - 1);
677  m.m_tty[sizeof(m.m_tty) - 1] = 0;
678  m.protocol_revision = MSG_REVISION;
679  debug1("SendErrorMsg(): writing to '%s'\n", SockPath);
680  (void) write(s, (char *) &m, sizeof m);
681  close(s);
682  return 0;
683}
684
685static void
686ExecCreate(mp)
687struct msg *mp;
688{
689  struct NewWindow nwin;
690  char *args[MAXARGS];
691  register int n;
692  register char **pp = args, *p = mp->m.create.line;
693
694  nwin = nwin_undef;
695  n = mp->m.create.nargs;
696  if (n > MAXARGS - 1)
697    n = MAXARGS - 1;
698  /* ugly hack alert... should be done by the frontend! */
699  if (n)
700    {
701      int l, num;
702      char buf[20];
703
704      l = strlen(p);
705      if (IsNumColon(p, 10, buf, sizeof(buf)))
706	{
707	  if (*buf)
708	    nwin.aka = buf;
709	  num = atoi(p);
710	  if (num < 0 || num > MAXWIN - 1)
711	    num = 0;
712	  nwin.StartAt = num;
713	  p += l + 1;
714	  n--;
715	}
716    }
717  for (; n > 0; n--)
718    {
719      *pp++ = p;
720      p += strlen(p) + 1;
721    }
722  *pp = 0;
723  if (*p)
724    nwin.aka = p;
725  if (*args)
726    nwin.args = args;
727  nwin.aflag = mp->m.create.aflag;
728  nwin.flowflag = mp->m.create.flowflag;
729  if (*mp->m.create.dir)
730    nwin.dir = mp->m.create.dir;
731  nwin.lflag = mp->m.create.lflag;
732  nwin.histheight = mp->m.create.hheight;
733  if (*mp->m.create.screenterm)
734    nwin.term =  mp->m.create.screenterm;
735  MakeWindow(&nwin);
736}
737
738static int
739CheckPid(pid)
740int pid;
741{
742  debug1("Checking pid %d\n", pid);
743  if (pid < 2)
744    return -1;
745  if (eff_uid == real_uid)
746    return kill(pid, 0);
747  if (UserContext() > 0)
748    UserReturn(kill(pid, 0));
749  return UserStatus();
750}
751
752#ifdef hpux
753/*
754 * From: "F. K. Bruner" <napalm@ugcs.caltech.edu>
755 * From: "Dan Egnor" <egnor@oracorp.com> Tue Aug 10 06:56:45 1993
756 * The problem is that under HPUX (and possibly other systems too) there are
757 * two equivalent device files for each pty/tty device:
758 * /dev/ttyxx == /dev/pty/ttyxx
759 * /dev/ptyxx == /dev/ptym/ptyxx
760 * I didn't look into the exact specifics, but I've run across this problem
761 * before: Even if you open /dev/ttyxx as fds 0 1 & 2 for a process, if that
762 * process calls the system to determine its tty, it'll get /dev/pty/ttyxx.
763 *
764 * Earlier versions seemed to work -- wonder what they did.
765 */
766static int
767ttycmp(s1, s2)
768char *s1, *s2;
769{
770  if (strlen(s1) > 5) s1 += strlen(s1) - 5;
771  if (strlen(s2) > 5) s2 += strlen(s2) - 5;
772  return strcmp(s1, s2);
773}
774# define TTYCMP(a, b) ttycmp(a, b)
775#else
776# define TTYCMP(a, b) strcmp(a, b)
777#endif
778
779void
780ReceiveMsg()
781{
782  int left, len, i;
783  static struct msg m;
784  char *p;
785  int ns = ServerSocket;
786  struct mode Mode;
787  struct win *wi;
788#ifdef REMOTE_DETACH
789  struct display *next;
790#endif
791  struct display *olddisplays = displays;
792
793#ifdef NAMEDPIPE
794  debug("Ha, there was someone knocking on my fifo??\n");
795  if (fcntl(ServerSocket, F_SETFL, 0) == -1)
796    Panic(errno, "BLOCK fcntl");
797#else
798  struct sockaddr_un a;
799
800  len = sizeof(a);
801  debug("Ha, there was someone knocking on my socket??\n");
802  if ((ns = accept(ns, (struct sockaddr *) &a, &len)) < 0)
803    {
804      Msg(errno, "accept");
805      return;
806    }
807#endif				/* NAMEDPIPE */
808
809  p = (char *) &m;
810  left = sizeof(m);
811  while (left > 0)
812    {
813      len = read(ns, p, left);
814      if (len < 0 && errno == EINTR)
815	continue;
816      if (len <= 0)
817	break;
818      p += len;
819      left -= len;
820    }
821
822#ifdef NAMEDPIPE
823# ifndef BROKEN_PIPE
824  /* Reopen pipe to prevent EOFs at the select() call */
825  close(ServerSocket);
826  if ((ServerSocket = secopen(SockPath, O_RDONLY | O_NONBLOCK, 0)) < 0)
827    Panic(errno, "reopen fifo %s", SockPath);
828  evdeq(&serv_read);
829  serv_read.fd = ServerSocket;
830  evenq(&serv_read);
831# endif
832#else
833  close(ns);
834#endif
835
836  if (len < 0)
837    {
838      Msg(errno, "read");
839      return;
840    }
841  if (left > 0)
842    {
843      if (left != sizeof(m))
844        Msg(0, "Message %d of %d bytes too small", left, (int)sizeof(m));
845      else
846	debug("No data on socket.\n");
847      return;
848    }
849  if (m.protocol_revision != MSG_REVISION)
850    {
851      Msg(0, "Invalid message (magic 0x%08x).", m.protocol_revision);
852      return;
853    }
854
855  debug2("*** RecMsg: type %d tty %s\n", m.type, m.m_tty);
856  for (display = displays; display; display = display->d_next)
857    if (TTYCMP(D_usertty, m.m_tty) == 0)
858      break;
859  debug2("display: %s display %sfound\n", m.m_tty, display ? "" : "not ");
860  wi = 0;
861  if (!display)
862    {
863      for (wi = windows; wi; wi = wi->w_next)
864        if (!TTYCMP(m.m_tty, wi->w_tty))
865	  {
866	    /* XXX: hmmm, rework this? */
867            display = wi->w_layer.l_cvlist ? wi->w_layer.l_cvlist->c_display : 0;
868	    debug2("but window %s %sfound.\n", m.m_tty, display ? "" :
869	    	   "(backfacing)");
870	    break;
871          }
872    }
873
874  /* Remove the status to prevent garbage on the screen */
875  if (display && D_status)
876    RemoveStatus();
877
878  if (display && !D_tcinited && m.type != MSG_HANGUP)
879    return;		/* ignore messages for bad displays */
880
881  switch (m.type)
882    {
883    case MSG_WINCH:
884      if (display)
885        CheckScreenSize(1); /* Change fore */
886      break;
887    case MSG_CREATE:
888      /*
889       * the window that issued the create message need not be an active
890       * window. Then we create the window without having a display.
891       * Resulting in another inactive window.
892       *
893       * Currently we enforce that at least one display exists. But why?
894       * jw.
895       */
896      if (displays)
897	ExecCreate(&m);
898      break;
899    case MSG_CONT:
900	if (display && D_userpid != 0 && kill(D_userpid, 0) == 0)
901	  break;		/* Intruder Alert */
902      debug2("RecMsg: apid=%d,was %d\n", m.m.attach.apid, display ? D_userpid : 0);
903      /* FALLTHROUGH */
904
905    case MSG_ATTACH:
906      if (CheckPid(m.m.attach.apid))
907	{
908	  Msg(0, "Attach attempt with bad pid(%d)!", m.m.attach.apid);
909          break;
910	}
911      if ((i = secopen(m.m_tty, O_RDWR | O_NONBLOCK, 0)) < 0)
912	{
913	  Msg(errno, "Attach: Could not open %s!", m.m_tty);
914	  Kill(m.m.attach.apid, SIG_BYE);
915	  break;
916	}
917# ifdef MULTIUSER
918      Kill(m.m.attach.apid, SIGCONT);
919# endif
920
921#if defined(ultrix) || defined(pyr) || defined(NeXT)
922      brktty(i);	/* for some strange reason this must be done */
923#endif
924
925      if (display || wi)
926	{
927	  write(i, "Attaching from inside of screen?\n", 33);
928	  close(i);
929	  Kill(m.m.attach.apid, SIG_BYE);
930	  Msg(0, "Attach msg ignored: coming from inside.");
931	  break;
932	}
933
934#ifdef MULTIUSER
935      if (strcmp(m.m.attach.auser, LoginName))
936        if (*FindUserPtr(m.m.attach.auser) == 0)
937	  {
938              write(i, "Access to session denied.\n", 26);
939	      close(i);
940	      Kill(m.m.attach.apid, SIG_BYE);
941	      Msg(0, "Attach: access denied for user %s.", m.m.attach.auser);
942	      break;
943	  }
944#endif
945
946      debug2("RecMsg: apid %d is o.k. and we just opened '%s'\n", m.m.attach.apid, m.m_tty);
947#ifndef MULTI
948      if (displays)
949	{
950	  write(i, "Screen session in use.\n", 23);
951	  close(i);
952	  Kill(m.m.attach.apid, SIG_BYE);
953	  break;
954	}
955#endif
956
957      /* create new display */
958      GetTTY(i, &Mode);
959      if (MakeDisplay(m.m.attach.auser, m.m_tty, m.m.attach.envterm, i, m.m.attach.apid, &Mode) == 0)
960        {
961	  write(i, "Could not make display.\n", 24);
962	  close(i);
963	  Msg(0, "Attach: could not make display for user %s", m.m.attach.auser);
964	  Kill(m.m.attach.apid, SIG_BYE);
965	  break;
966        }
967#ifdef ENCODINGS
968# ifdef UTF8
969      D_encoding = m.m.attach.encoding == 1 ? UTF8 : m.m.attach.encoding ? m.m.attach.encoding - 1 : 0;
970# else
971      D_encoding = m.m.attach.encoding ? m.m.attach.encoding - 1 : 0;
972# endif
973      if (D_encoding < 0 || !EncodingName(D_encoding))
974	D_encoding = 0;
975#endif
976      /* turn off iflag on a multi-attach... */
977      if (iflag && olddisplays)
978	{
979	  iflag = 0;
980#if defined(TERMIO) || defined(POSIX)
981	  olddisplays->d_NewMode.tio.c_cc[VINTR] = VDISABLE;
982	  olddisplays->d_NewMode.tio.c_lflag &= ~ISIG;
983#else /* TERMIO || POSIX */
984	  olddisplays->d_NewMode.m_tchars.t_intrc = -1;
985#endif /* TERMIO || POSIX */
986	  SetTTY(olddisplays->d_userfd, &olddisplays->d_NewMode);
987	}
988      SetMode(&D_OldMode, &D_NewMode, D_flow, iflag);
989      SetTTY(D_userfd, &D_NewMode);
990      if (fcntl(D_userfd, F_SETFL, FNBLOCK))
991        Msg(errno, "Warning: NBLOCK fcntl failed");
992
993#ifdef PASSWORD
994      if (D_user->u_password && *D_user->u_password)
995	AskPassword(&m);
996      else
997#endif
998        FinishAttach(&m);
999      break;
1000    case MSG_ERROR:
1001      Msg(0, "%s", m.m.message);
1002      break;
1003    case MSG_HANGUP:
1004      if (!wi)		/* ignore hangups from inside */
1005        Hangup();
1006      break;
1007#ifdef REMOTE_DETACH
1008    case MSG_DETACH:
1009# ifdef POW_DETACH
1010    case MSG_POW_DETACH:
1011# endif				/* POW_DETACH */
1012      for (display = displays; display; display = next)
1013	{
1014	  next = display->d_next;
1015# ifdef POW_DETACH
1016	  if (m.type == MSG_POW_DETACH)
1017	    Detach(D_REMOTE_POWER);
1018	  else
1019# endif				/* POW_DETACH */
1020	  if (m.type == MSG_DETACH)
1021	    Detach(D_REMOTE);
1022	}
1023      break;
1024#endif
1025    case MSG_COMMAND:
1026      DoCommandMsg(&m);
1027      break;
1028    default:
1029      Msg(0, "Invalid message (type %d).", m.type);
1030    }
1031}
1032
1033#if defined(_SEQUENT_) && !defined(NAMEDPIPE)
1034#undef connect
1035/*
1036 *  sequent_ptx socket emulation must have mode 000 on the socket!
1037 */
1038static int
1039sconnect(s, sapp, len)
1040int s, len;
1041struct sockaddr *sapp;
1042{
1043  register struct sockaddr_un *sap;
1044  struct stat st;
1045  int x;
1046
1047  sap = (struct sockaddr_un *)sapp;
1048  if (stat(sap->sun_path, &st))
1049    return -1;
1050  chmod(sap->sun_path, 0);
1051  x = connect(s, (struct sockaddr *) sap, len);
1052  chmod(sap->sun_path, st.st_mode);
1053  return x;
1054}
1055#endif
1056
1057
1058/*
1059 * Set the mode bits of the socket to the current status
1060 */
1061int
1062chsock()
1063{
1064  int r, euid = geteuid();
1065  if (euid != real_uid)
1066    {
1067      if (UserContext() <= 0)
1068        return UserStatus();
1069    }
1070  r = chmod(SockPath, SOCKMODE);
1071  /*
1072   * Sockets usually reside in the /tmp/ area, where sysadmin scripts
1073   * may be happy to remove old files. We manually prevent the socket
1074   * from becoming old. (chmod does not touch mtime).
1075   */
1076  (void)utimes(SockPath, NULL);
1077
1078  if (euid != real_uid)
1079    UserReturn(r);
1080  return r;
1081}
1082
1083/*
1084 * Try to recreate the socket/pipe
1085 */
1086int
1087RecoverSocket()
1088{
1089  close(ServerSocket);
1090  if ((int)geteuid() != real_uid)
1091    {
1092      if (UserContext() > 0)
1093	UserReturn(unlink(SockPath));
1094      (void)UserStatus();
1095    }
1096  else
1097    (void) unlink(SockPath);
1098
1099  if ((ServerSocket = MakeServerSocket()) < 0)
1100    return 0;
1101  evdeq(&serv_read);
1102  serv_read.fd = ServerSocket;
1103  evenq(&serv_read);
1104  return 1;
1105}
1106
1107
1108static void
1109FinishAttach(m)
1110struct msg *m;
1111{
1112  char *p;
1113  int pid;
1114  int noshowwin;
1115
1116#ifndef __APPLE__
1117  struct win *wi;
1118#endif
1119
1120  ASSERT(display);
1121  pid = D_userpid;
1122
1123#if defined(pyr) || defined(xelos) || defined(sequent)
1124  /*
1125   * Kludge for systems with braindamaged termcap routines,
1126   * which evaluate $TERMCAP, regardless weather it describes
1127   * the correct terminal type or not.
1128   */
1129  debug("unsetenv(TERMCAP) in case of a different terminal");
1130  unsetenv("TERMCAP");
1131#endif
1132
1133  /*
1134   * We reboot our Terminal Emulator. Forget all we knew about
1135   * the old terminal, reread the termcap entries in .screenrc
1136   * (and nothing more from .screenrc is read. Mainly because
1137   * I did not check, weather a full reinit is safe. jw)
1138   * and /etc/screenrc, and initialise anew.
1139   */
1140  if (extra_outcap)
1141    free(extra_outcap);
1142  if (extra_incap)
1143    free(extra_incap);
1144  extra_incap = extra_outcap = 0;
1145  debug2("Message says size (%dx%d)\n", m->m.attach.columns, m->m.attach.lines);
1146#ifdef ETCSCREENRC
1147# ifdef ALLOW_SYSSCREENRC
1148  if ((p = getenv("SYSSCREENRC")))
1149    StartRc(p);
1150  else
1151# endif
1152    StartRc(ETCSCREENRC);
1153#endif
1154  StartRc(RcFileName);
1155  if (InitTermcap(m->m.attach.columns, m->m.attach.lines))
1156    {
1157      FreeDisplay();
1158      Kill(pid, SIG_BYE);
1159      return;
1160    }
1161  MakeDefaultCanvas();
1162  InitTerm(m->m.attach.adaptflag);	/* write init string on fd */
1163  if (displays->d_next == 0)
1164    (void) chsock();
1165  signal(SIGHUP, SigHup);
1166  if (m->m.attach.esc != -1 && m->m.attach.meta_esc != -1)
1167    {
1168      D_user->u_Esc = m->m.attach.esc;
1169      D_user->u_MetaEsc = m->m.attach.meta_esc;
1170    }
1171
1172#ifdef UTMPOK
1173  /*
1174   * we set the Utmp slots again, if we were detached normally
1175   * and if we were detached by ^Z.
1176   * don't log zomies back in!
1177   */
1178  RemoveLoginSlot();
1179  if (displays->d_next == 0)
1180    for (wi = windows; wi; wi = wi->w_next)
1181      if (wi->w_ptyfd >= 0 && wi->w_slot != (slot_t) -1)
1182	SetUtmp(wi);
1183#endif
1184
1185  D_fore = NULL;
1186  /*
1187   * there may be a window that we remember from last detach:
1188   */
1189  debug1("D_user->u_detachwin = %d\n", D_user->u_detachwin);
1190  if (D_user->u_detachwin >= 0)
1191    fore = wtab[D_user->u_detachwin];
1192  else
1193    fore = 0;
1194
1195  /* Wayne wants us to restore the other window too. */
1196  if (D_user->u_detachotherwin >= 0)
1197    D_other = wtab[D_user->u_detachotherwin];
1198
1199  noshowwin = 0;
1200  if (*m->m.attach.preselect)
1201    {
1202      if (!strcmp(m->m.attach.preselect, "="))
1203        fore = 0;
1204      else if (!strcmp(m->m.attach.preselect, "-"))
1205	{
1206          fore = 0;
1207	  noshowwin = 1;
1208	}
1209      else
1210        fore = FindNiceWindow(fore, m->m.attach.preselect);
1211    }
1212  else
1213    fore = FindNiceWindow(fore, 0);
1214  if (fore)
1215    SetForeWindow(fore);
1216  else if (!noshowwin)
1217    {
1218#ifdef MULTIUSER
1219      if (!AclCheckPermCmd(D_user, ACL_EXEC, &comms[RC_WINDOWLIST]))
1220#endif
1221	{
1222	  flayer = D_forecv->c_layer;
1223	  display_wlist(1, WLIST_NUM);
1224	  noshowwin = 1;
1225	}
1226    }
1227  Activate(0);
1228  ResetIdle();
1229  if (!D_fore && !noshowwin)
1230    ShowWindows(-1);
1231  if (displays->d_next == 0 && console_window)
1232    {
1233      if (TtyGrabConsole(console_window->w_ptyfd, 1, "reattach") == 0)
1234	Msg(0, "console %s is on window %d", HostName, console_window->w_number);
1235    }
1236  debug("activated...\n");
1237
1238# if defined(DEBUG) && defined(SIG_NODEBUG)
1239  if (!dfp)
1240    {
1241      sleep(1);
1242      debug1("Attacher %d must not debug, as we have debug off.\n", pid);
1243      kill(pid, SIG_NODEBUG);
1244    }
1245# endif /* SIG_NODEBUG */
1246}
1247
1248
1249#ifdef PASSWORD
1250static void PasswordProcessInput __P((char *, int));
1251
1252struct pwdata {
1253  int l;
1254  char buf[20 + 1];
1255  struct msg m;
1256};
1257
1258static void
1259AskPassword(m)
1260struct msg *m;
1261{
1262  struct pwdata *pwdata;
1263  ASSERT(display);
1264  pwdata = (struct pwdata *)malloc(sizeof(struct pwdata));
1265  if (!pwdata)
1266    Panic(0, strnomem);
1267  pwdata->l = 0;
1268  pwdata->m = *m;
1269  D_processinputdata = (char *)pwdata;
1270  D_processinput = PasswordProcessInput;
1271  AddStr("Screen password: ");
1272}
1273
1274static void
1275PasswordProcessInput(ibuf, ilen)
1276char *ibuf;
1277int ilen;
1278{
1279  struct pwdata *pwdata;
1280  int c, l;
1281  char *up;
1282  int pid = D_userpid;
1283
1284  pwdata = (struct pwdata *)D_processinputdata;
1285  l = pwdata->l;
1286  while (ilen-- > 0)
1287    {
1288      c = *(unsigned char *)ibuf++;
1289      if (c == '\r' || c == '\n')
1290	{
1291	  up = D_user->u_password;
1292	  pwdata->buf[l] = 0;
1293	  if (strncmp(crypt(pwdata->buf, up), up, strlen(up)))
1294	    {
1295	      /* uh oh, user failed */
1296	      bzero(pwdata->buf, sizeof(pwdata->buf));
1297	      AddStr("\r\nPassword incorrect.\r\n");
1298	      D_processinputdata = 0;	/* otherwise freed by FreeDis */
1299	      FreeDisplay();
1300	      Msg(0, "Illegal reattach attempt from terminal %s.", pwdata->m.m_tty);
1301	      free(pwdata);
1302	      Kill(pid, SIG_BYE);
1303	      return;
1304	    }
1305	  /* great, pw matched, all is fine */
1306	  bzero(pwdata->buf, sizeof(pwdata->buf));
1307	  AddStr("\r\n");
1308	  D_processinputdata = 0;
1309	  D_processinput = ProcessInput;
1310	  FinishAttach(&pwdata->m);
1311	  free(pwdata);
1312	  return;
1313	}
1314      if (c == Ctrl('c'))
1315	{
1316	  AddStr("\r\n");
1317	  FreeDisplay();
1318	  Kill(pid, SIG_BYE);
1319	  return;
1320	}
1321      if (c == '\b' || c == 0177)
1322	{
1323	  if (l > 0)
1324	    l--;
1325	  continue;
1326	}
1327      if (c == Ctrl('u'))
1328	{
1329	  l = 0;
1330	  continue;
1331	}
1332      if (l < (int)sizeof(pwdata->buf) - 1)
1333	pwdata->buf[l++] = c;
1334    }
1335  pwdata->l = l;
1336}
1337#endif
1338
1339static void
1340DoCommandMsg(mp)
1341struct msg *mp;
1342{
1343  char *args[MAXARGS];
1344  int argl[MAXARGS];
1345  int n, *lp;
1346  register char **pp = args, *p = mp->m.command.cmd;
1347  struct acluser *user;
1348#ifdef MULTIUSER
1349  extern struct acluser *EffectiveAclUser;	/* acls.c */
1350#else
1351  extern struct acluser *users;			/* acls.c */
1352#endif
1353
1354  lp = argl;
1355  n = mp->m.command.nargs;
1356  if (n > MAXARGS - 1)
1357    n = MAXARGS - 1;
1358  for (; n > 0; n--)
1359    {
1360      *pp++ = p;
1361      *lp = strlen(p);
1362      p += *lp++ + 1;
1363    }
1364  *pp = 0;
1365#ifdef MULTIUSER
1366  user = *FindUserPtr(mp->m.attach.auser);
1367  if (user == 0)
1368    {
1369      Msg(0, "Unknown user %s tried to send a command!", mp->m.attach.auser);
1370      return;
1371    }
1372#else
1373  user = users;
1374#endif
1375#ifdef PASSWORD
1376  if (user->u_password && *user->u_password)
1377    {
1378      Msg(0, "User %s has a password, cannot use -X option.", mp->m.attach.auser);
1379      return;
1380    }
1381#endif
1382  if (!display)
1383    for (display = displays; display; display = display->d_next)
1384      if (D_user == user)
1385	break;
1386  for (fore = windows; fore; fore = fore->w_next)
1387    if (!TTYCMP(mp->m_tty, fore->w_tty))
1388      {
1389	if (!display)
1390	  display = fore->w_layer.l_cvlist ? fore->w_layer.l_cvlist->c_display : 0;
1391	break;
1392      }
1393  if (!display)
1394    display = displays;		/* sigh */
1395  if (*mp->m.command.preselect)
1396    {
1397      int i = -1;
1398      if (strcmp(mp->m.command.preselect, "-"))
1399        i = WindowByNoN(mp->m.command.preselect);
1400      fore = i >= 0 ? wtab[i] : 0;
1401    }
1402  else if (!fore)
1403    {
1404      if (display && D_user == user)
1405	fore = Layer2Window(display->d_forecv->c_layer);
1406      if (!fore)
1407	{
1408	  fore = user->u_detachwin >= 0 ? wtab[user->u_detachwin] : 0;
1409	  fore = FindNiceWindow(fore, 0);
1410	}
1411    }
1412#ifdef MULTIUSER
1413  EffectiveAclUser = user;
1414#endif
1415  if (*args)
1416    {
1417      char *oldrcname = rc_name;
1418      rc_name = "-X";
1419      debug3("Running command on display %x window %x (%d)\n", display, fore, fore ? fore->w_number : -1);
1420      flayer = fore ? &fore->w_layer : 0;
1421      if (fore && fore->w_savelayer && (fore->w_blocked || fore->w_savelayer->l_cvlist == 0))
1422	flayer = fore->w_savelayer;
1423      DoCommand(args, argl);
1424      rc_name = oldrcname;
1425    }
1426#ifdef MULTIUSER
1427  EffectiveAclUser = 0;
1428#endif
1429}
1430