server_pty.c 5.01 KB
Newer Older
1
/* server_pty.c
Niels Möller's avatar
Niels Möller committed
2
3
4
5
6
 *
 */

/* lsh, an implementation of the ssh protocol
 *
7
 * Copyright (C) 1998, 1999, Niels Mller, Balzs Scheidler
Niels Möller's avatar
Niels Möller committed
8
9
10
11
12
13
14
15
16
17
18
19
20
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
21
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Niels Möller's avatar
Niels Möller committed
22
23
 */

24
25
26
#if HAVE_CONFIG_H
#include "config.h"
#endif
Niels Möller's avatar
Niels Möller committed
27

28
#include <errno.h>
Niels Möller's avatar
Niels Möller committed
29
30

#include <fcntl.h>
31
#include <grp.h>
32
33
#include <unistd.h>
#include <sys/types.h>
Niels Möller's avatar
Niels Möller committed
34
#include <sys/ioctl.h>
35
#include <sys/stat.h>
Niels Möller's avatar
Niels Möller committed
36

37
38
#if HAVE_STROPTS_H
# include <stropts.h>  /* isastream() */
39
40
#endif

41
42
43
44
45
46
47
48
49
50
/* Kludge... On Solaris, including termios.h brings in a compatibility
   definition of TIOCSCTTY, which doesn't work. So check if it's
   defined before the includes that bring in termios.h. */

#ifdef TIOCSCTTY
# define HAVE_TIOCSCTTY 1
#else
# define HAVE_TIOCSCTTY 0
#endif

51
52
53
54
#include "server_pty.h"

#include "channel.h"
#include "format.h"
55
#include "io.h"
56
#include "lsh_string.h"
57
58
#include "parse.h"
#include "ssh.h"
59
#include "tty.h"
60
61
62
#include "werror.h"
#include "xalloc.h"

63

64
#define GABA_DEFINE
Niels Möller's avatar
Niels Möller committed
65
#include "server_pty.h.x"
66
#undef GABA_DEFINE
Niels Möller's avatar
Niels Möller committed
67

68
69
static void
do_kill_pty_info(struct resource *r)
Niels Möller's avatar
Niels Möller committed
70
{
71
  CAST(pty_info, pty, r);
Niels Möller's avatar
Niels Möller committed
72

73
  if (pty->super.alive)
Niels Möller's avatar
Niels Möller committed
74
    {
75
76
      pty->super.alive = 0;
      if ( (pty->master >= 0) && (close(pty->master) < 0) )
77
	werror("do_kill_pty_info: closing master failed: %e.\n", errno);
Niels Möller's avatar
Niels Möller committed
78
79
80
    }
}

81
82
struct pty_info *
make_pty_info(void)
Niels Möller's avatar
Niels Möller committed
83
84
85
{
  NEW(pty_info, pty);

86
  init_resource(&pty->super, do_kill_pty_info);
87
  pty->tty_name = NULL;
88
89
  pty->mode = NULL;
  pty->master = -1;
Niels Möller's avatar
Niels Möller committed
90
91
92
  return pty;
}

93
int
94
pty_open_master(struct pty_info *pty)
95
96
{
#if HAVE_UNIX98_PTYS
97
  if ((pty->master = open("/dev/ptmx", O_RDWR | O_NOCTTY)) < 0)
98
    {
99
      werror("pty_open_master: Opening /dev/ptmx failed: %e.\n", errno);
100
101
      return 0;
    }
102

103
104
  if (grantpt(pty->master) < 0)
    {
105
      werror ("grantpt failed: %e.\n", errno);
106
107
108
109
110
111
      
    error:
      close (pty->master); pty->master = -1;
      return 0;
    }
  if (unlockpt(pty->master) < 0)
112
    {
113
      werror ("unlockpt failed: %e.\n", errno);
114
      goto error;
115
116
    }

117
118
119
120
121
  io_set_close_on_exec(pty->master);
  
  pty->tty_name = make_string(ptsname(pty->master));
  return 1;

122
#endif
123

Niels Möller's avatar
Niels Möller committed
124
125
126
127
  /* FIXME: Traditional BSD-style pty:s not implemented. Needs to ask
     the pty_helper process to open the master for us and setup the
     permissions, and then that procecss must run as root. */
  
Niels Möller's avatar
Niels Möller committed
128
129
130
  return 0;
}

131
132
133
134
135
136
/* Opens the slave side of the tty, intitializes it, and makes it our
 * controlling terminal. Should be called by the child process.
 *
 * Also makes the current process a session leader.
 *
 * Returns an fd, or -1 on error. */
137
int
138
pty_open_slave(struct pty_info *pty)
139
{
140
141
142
143
144
145
146
147
148
149
  struct termios ios;
  int fd;
  
  trace("pty_open_slave\n");

  /* Open the slave. On Sys V, that also makes it our controlling tty. */
  fd = open(lsh_get_cstring(pty->tty_name), O_RDWR);

  if (fd < 0)
    {
150
      werror("pty_open_slave: open(\"%S\") failed: %e.\n",
151
	     pty->tty_name, errno);
152
153
      return -1;
    }
154

155
156
  io_set_close_on_exec(fd);

157
158
159
160
161
  /* For Sys V and Solaris, push some streams modules.
   * This seems to also have the side effect of making the
   * tty become our controlling terminal. */
# ifdef HAVE_STROPTS_H
  if (isastream(fd))
162
163
164
    {
      if (ioctl(fd, I_PUSH, "ptem") < 0)
	{
165
	  werror("pty_open_slave: Failed to push streams module `ptem': %e.\n", errno);
166
167
168
169
170
171
	
	  close(fd);
	  return -1;
	}
      if (ioctl(fd, I_PUSH, "ldterm") < 0)
	{
172
	  werror("pty_open_slave: Failed to push streams module `ldterm': %e.\n", errno);
173
174
175
176
177
	
	  close(fd);
	  return -1;
	}
    }
178
179
180
181
# endif /* HAVE_STROPTS_H */

  /* On BSD systems, use TIOCSCTTY. */

182
#if HAVE_TIOCSCTTY
183
184
  if (ioctl(fd, TIOCSCTTY, NULL) < 0)
    {
185
      werror("pty_open_slave: Failed to set the controlling tty: %e.\n", errno);
186
187
188
189
190
191
      close(fd);
      return -1;
    }
#endif /* defined(TIOCSCTTY) */

  /* Set terminal modes */
192
  if (!tcgetattr(fd, &ios) == -1)
193
    {
194
      werror("pty_open_slave: Failed to get tty attributes: %e.\n", errno);
195
196
197
      close(fd);
      return -1;
    }
198

199
200
201
202
203
  if (!tty_decode_term_mode(&ios, STRING_LD(pty->mode)))
    {
      werror("pty_open_slave: Invalid terminal modes from client.\n");
      close(fd);
      return -1;
204
    }
205

206
  if (!tcsetattr(fd, TCSADRAIN, &ios) == -1)
207
    {
208
      werror("pty_open_slave: Failed to set tty attributes: %e.\n", errno);
209
210
211
      close(fd);
      return -1;
    }
212
213

  if (ioctl(fd, TIOCSWINSZ, &pty->dims) == -1)  
214
    {
215
      werror("pty_open_slave: Failed to set tty window size: %e.\n", errno);
216
217
218
219
220
      close(fd);
      return -1;
    }

  return fd;
221
}