ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sshpty.c
Revision: 1.1
Committed: 2002-07-31T16:46:14Z (21 years, 11 months ago) by cebix
Content type: text/plain
Branch: MAIN
CVS Tags: nigel-build-12, nigel-build-13
Log Message:
- it is now possible to make the serial drivers pipe their input/output
  to programs by using a '|' followed by a command line as the modem or
  printer port setting (instead of a device name like '/dev/ttyS0')
  [Brian Johnson]
- the option "--config FILE" tells B2 to use a different config file

File Contents

# Content
1 /*
2 * Author: Tatu Ylonen <ylo@cs.hut.fi>
3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 * All rights reserved
5 * Allocating a pseudo-terminal, and making it the controlling tty.
6 *
7 * As far as I am concerned, the code I have written for this software
8 * can be used freely for any purpose. Any derived versions of this
9 * software must be clearly marked as such, and if the derived work is
10 * incompatible with the protocol description in the RFC file, it must be
11 * called by a name other than "ssh" or "Secure Shell".
12 */
13
14 #if 0 /* not in BasiliskII */
15 #include "includes.h"
16 RCSID("$OpenBSD: sshpty.c,v 1.4 2001/12/19 07:18:56 deraadt Exp $");
17 #else /* not in BasiliskII */
18 /* Selections from openssh's "includes.h" */
19 #include "config.h"
20
21 #include <stdio.h>
22 #include <ctype.h>
23 #include <errno.h>
24 #include <fcntl.h> /* For O_NONBLOCK */
25 #include <stdlib.h>
26 #include <string.h>
27 #include <pwd.h>
28
29 #include <unistd.h> /* For STDIN_FILENO, etc */
30 #include <termios.h> /* Struct winsize */
31
32 /*
33 *-*-nto-qnx needs these headers for strcasecmp and LASTLOG_FILE respectively
34 */
35 #ifdef HAVE_STRINGS_H
36 # include <strings.h>
37 #endif
38 #ifdef HAVE_LOGIN_H
39 # include <login.h>
40 #endif
41
42 #include <sys/ioctl.h>
43
44 #ifdef HAVE_SYS_BSDTTY_H
45 # include <sys/bsdtty.h>
46 #endif
47
48 #ifdef HAVE_SYS_STAT_H
49 # include <sys/stat.h> /* For S_* constants and macros */
50 #endif
51
52 #ifndef _PATH_TTY
53 # define _PATH_TTY "/dev/tty"
54 #endif
55
56 #include "strlcpy.h"
57
58 #define debug(x) ;
59
60 #endif /* not in BasiliskII */
61
62 #ifdef HAVE_UTIL_H
63 # include <util.h>
64 #endif /* HAVE_UTIL_H */
65
66 #include "sshpty.h"
67 #if 0 /* not in BasiliskII */
68 #include "log.h"
69 #include "misc.h"
70 #else /* stubs for BasiliskII */
71 #define error printf
72 #define fatal(x) {printf("Fatal error: %s", x); return 0}
73 #endif /* not in BasiliskII */
74
75 /* Pty allocated with _getpty gets broken if we do I_PUSH:es to it. */
76 #if defined(HAVE__GETPTY) || defined(HAVE_OPENPTY)
77 #undef HAVE_DEV_PTMX
78 #endif
79
80 #ifdef HAVE_PTY_H
81 # include <pty.h>
82 #endif
83 #if defined(HAVE_DEV_PTMX) && defined(HAVE_SYS_STROPTS_H)
84 # include <sys/stropts.h>
85 #endif
86
87 #ifndef O_NOCTTY
88 #define O_NOCTTY 0
89 #endif
90
91 /*
92 * Allocates and opens a pty. Returns 0 if no pty could be allocated, or
93 * nonzero if a pty was successfully allocated. On success, open file
94 * descriptors for the pty and tty sides and the name of the tty side are
95 * returned (the buffer must be able to hold at least 64 characters).
96 */
97
98 int
99 pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen)
100 {
101 #if defined(HAVE_OPENPTY) || defined(BSD4_4)
102 /* openpty(3) exists in OSF/1 and some other os'es */
103 char *name;
104 int i;
105
106 i = openpty(ptyfd, ttyfd, NULL, NULL, NULL);
107 if (i < 0) {
108 error("openpty: %.100s", strerror(errno));
109 return 0;
110 }
111 name = ttyname(*ttyfd);
112 if (!name)
113 fatal("openpty returns device for which ttyname fails.");
114
115 strlcpy(namebuf, name, namebuflen); /* possible truncation */
116 return 1;
117 #else /* HAVE_OPENPTY */
118 #ifdef HAVE__GETPTY
119 /*
120 * _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more
121 * pty's automagically when needed
122 */
123 char *slave;
124
125 slave = _getpty(ptyfd, O_RDWR, 0622, 0);
126 if (slave == NULL) {
127 error("_getpty: %.100s", strerror(errno));
128 return 0;
129 }
130 strlcpy(namebuf, slave, namebuflen);
131 /* Open the slave side. */
132 *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
133 if (*ttyfd < 0) {
134 error("%.200s: %.100s", namebuf, strerror(errno));
135 close(*ptyfd);
136 return 0;
137 }
138 return 1;
139 #else /* HAVE__GETPTY */
140 #if defined(HAVE_DEV_PTMX)
141 /*
142 * This code is used e.g. on Solaris 2.x. (Note that Solaris 2.3
143 * also has bsd-style ptys, but they simply do not work.)
144 */
145 int ptm;
146 char *pts;
147 mysig_t old_signal;
148
149 ptm = open("/dev/ptmx", O_RDWR | O_NOCTTY);
150 if (ptm < 0) {
151 error("/dev/ptmx: %.100s", strerror(errno));
152 return 0;
153 }
154 old_signal = mysignal(SIGCHLD, SIG_DFL);
155 if (grantpt(ptm) < 0) {
156 error("grantpt: %.100s", strerror(errno));
157 return 0;
158 }
159 mysignal(SIGCHLD, old_signal);
160 if (unlockpt(ptm) < 0) {
161 error("unlockpt: %.100s", strerror(errno));
162 return 0;
163 }
164 pts = ptsname(ptm);
165 if (pts == NULL)
166 error("Slave pty side name could not be obtained.");
167 strlcpy(namebuf, pts, namebuflen);
168 *ptyfd = ptm;
169
170 /* Open the slave side. */
171 *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
172 if (*ttyfd < 0) {
173 error("%.100s: %.100s", namebuf, strerror(errno));
174 close(*ptyfd);
175 return 0;
176 }
177 #ifndef HAVE_CYGWIN
178 /*
179 * Push the appropriate streams modules, as described in Solaris pts(7).
180 * HP-UX pts(7) doesn't have ttcompat module.
181 */
182 if (ioctl(*ttyfd, I_PUSH, "ptem") < 0)
183 error("ioctl I_PUSH ptem: %.100s", strerror(errno));
184 if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0)
185 error("ioctl I_PUSH ldterm: %.100s", strerror(errno));
186 #ifndef __hpux
187 if (ioctl(*ttyfd, I_PUSH, "ttcompat") < 0)
188 error("ioctl I_PUSH ttcompat: %.100s", strerror(errno));
189 #endif
190 #endif
191 return 1;
192 #else /* HAVE_DEV_PTMX */
193 #ifdef HAVE_DEV_PTS_AND_PTC
194 /* AIX-style pty code. */
195 const char *name;
196
197 *ptyfd = open("/dev/ptc", O_RDWR | O_NOCTTY);
198 if (*ptyfd < 0) {
199 error("Could not open /dev/ptc: %.100s", strerror(errno));
200 return 0;
201 }
202 name = ttyname(*ptyfd);
203 if (!name)
204 fatal("Open of /dev/ptc returns device for which ttyname fails.");
205 strlcpy(namebuf, name, namebuflen);
206 *ttyfd = open(name, O_RDWR | O_NOCTTY);
207 if (*ttyfd < 0) {
208 error("Could not open pty slave side %.100s: %.100s",
209 name, strerror(errno));
210 close(*ptyfd);
211 return 0;
212 }
213 return 1;
214 #else /* HAVE_DEV_PTS_AND_PTC */
215 #ifdef _CRAY
216 char buf[64];
217 int i;
218 int highpty;
219
220 #ifdef _SC_CRAY_NPTY
221 highpty = sysconf(_SC_CRAY_NPTY);
222 if (highpty == -1)
223 highpty = 128;
224 #else
225 highpty = 128;
226 #endif
227
228 for (i = 0; i < highpty; i++) {
229 snprintf(buf, sizeof(buf), "/dev/pty/%03d", i);
230 *ptyfd = open(buf, O_RDWR|O_NOCTTY);
231 if (*ptyfd < 0)
232 continue;
233 snprintf(namebuf, namebuflen, "/dev/ttyp%03d", i);
234 /* Open the slave side. */
235 *ttyfd = open(namebuf, O_RDWR|O_NOCTTY);
236 if (*ttyfd < 0) {
237 error("%.100s: %.100s", namebuf, strerror(errno));
238 close(*ptyfd);
239 return 0;
240 }
241 return 1;
242 }
243 return 0;
244 #else
245 /* BSD-style pty code. */
246 char buf[64];
247 int i;
248 const char *ptymajors = "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
249 const char *ptyminors = "0123456789abcdef";
250 int num_minors = strlen(ptyminors);
251 int num_ptys = strlen(ptymajors) * num_minors;
252 struct termios tio;
253
254 for (i = 0; i < num_ptys; i++) {
255 snprintf(buf, sizeof buf, "/dev/pty%c%c", ptymajors[i / num_minors],
256 ptyminors[i % num_minors]);
257 snprintf(namebuf, namebuflen, "/dev/tty%c%c",
258 ptymajors[i / num_minors], ptyminors[i % num_minors]);
259
260 *ptyfd = open(buf, O_RDWR | O_NOCTTY);
261 if (*ptyfd < 0) {
262 /* Try SCO style naming */
263 snprintf(buf, sizeof buf, "/dev/ptyp%d", i);
264 snprintf(namebuf, namebuflen, "/dev/ttyp%d", i);
265 *ptyfd = open(buf, O_RDWR | O_NOCTTY);
266 if (*ptyfd < 0)
267 continue;
268 }
269
270 /* Open the slave side. */
271 *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
272 if (*ttyfd < 0) {
273 error("%.100s: %.100s", namebuf, strerror(errno));
274 close(*ptyfd);
275 return 0;
276 }
277 /* set tty modes to a sane state for broken clients */
278 if (tcgetattr(*ptyfd, &tio) < 0)
279 log("Getting tty modes for pty failed: %.100s", strerror(errno));
280 else {
281 tio.c_lflag |= (ECHO | ISIG | ICANON);
282 tio.c_oflag |= (OPOST | ONLCR);
283 tio.c_iflag |= ICRNL;
284
285 /* Set the new modes for the terminal. */
286 if (tcsetattr(*ptyfd, TCSANOW, &tio) < 0)
287 log("Setting tty modes for pty failed: %.100s", strerror(errno));
288 }
289
290 return 1;
291 }
292 return 0;
293 #endif /* CRAY */
294 #endif /* HAVE_DEV_PTS_AND_PTC */
295 #endif /* HAVE_DEV_PTMX */
296 #endif /* HAVE__GETPTY */
297 #endif /* HAVE_OPENPTY */
298 }
299
300 /* Releases the tty. Its ownership is returned to root, and permissions to 0666. */
301
302 void
303 pty_release(const char *ttyname)
304 {
305 if (chown(ttyname, (uid_t) 0, (gid_t) 0) < 0)
306 error("chown %.100s 0 0 failed: %.100s", ttyname, strerror(errno));
307 if (chmod(ttyname, (mode_t) 0666) < 0)
308 error("chmod %.100s 0666 failed: %.100s", ttyname, strerror(errno));
309 }
310
311 /* Makes the tty the processes controlling tty and sets it to sane modes. */
312
313 void
314 pty_make_controlling_tty(int *ttyfd, const char *ttyname)
315 {
316 int fd;
317 #ifdef USE_VHANGUP
318 void *old;
319 #endif /* USE_VHANGUP */
320
321 #ifdef _CRAY
322 if (setsid() < 0)
323 error("setsid: %.100s", strerror(errno));
324
325 fd = open(ttyname, O_RDWR|O_NOCTTY);
326 if (fd != -1) {
327 mysignal(SIGHUP, SIG_IGN);
328 ioctl(fd, TCVHUP, (char *)NULL);
329 mysignal(SIGHUP, SIG_DFL);
330 setpgid(0, 0);
331 close(fd);
332 } else {
333 error("Failed to disconnect from controlling tty.");
334 }
335
336 debug("Setting controlling tty using TCSETCTTY.");
337 ioctl(*ttyfd, TCSETCTTY, NULL);
338 fd = open("/dev/tty", O_RDWR);
339 if (fd < 0)
340 error("%.100s: %.100s", ttyname, strerror(errno));
341 close(*ttyfd);
342 *ttyfd = fd;
343 #else /* _CRAY */
344
345 /* First disconnect from the old controlling tty. */
346 #ifdef TIOCNOTTY
347 fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
348 if (fd >= 0) {
349 (void) ioctl(fd, TIOCNOTTY, NULL);
350 close(fd);
351 }
352 #endif /* TIOCNOTTY */
353 if (setsid() < 0)
354 error("setsid: %.100s", strerror(errno));
355
356 /*
357 * Verify that we are successfully disconnected from the controlling
358 * tty.
359 */
360 fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
361 if (fd >= 0) {
362 error("Failed to disconnect from controlling tty.");
363 close(fd);
364 }
365 /* Make it our controlling tty. */
366 #ifdef TIOCSCTTY
367 debug("Setting controlling tty using TIOCSCTTY.");
368 if (ioctl(*ttyfd, TIOCSCTTY, NULL) < 0)
369 error("ioctl(TIOCSCTTY): %.100s", strerror(errno));
370 #endif /* TIOCSCTTY */
371 #ifdef HAVE_NEWS4
372 if (setpgrp(0,0) < 0)
373 error("SETPGRP %s",strerror(errno));
374 #endif /* HAVE_NEWS4 */
375 #ifdef USE_VHANGUP
376 old = mysignal(SIGHUP, SIG_IGN);
377 vhangup();
378 mysignal(SIGHUP, old);
379 #endif /* USE_VHANGUP */
380 fd = open(ttyname, O_RDWR);
381 if (fd < 0) {
382 error("%.100s: %.100s", ttyname, strerror(errno));
383 } else {
384 #ifdef USE_VHANGUP
385 close(*ttyfd);
386 *ttyfd = fd;
387 #else /* USE_VHANGUP */
388 close(fd);
389 #endif /* USE_VHANGUP */
390 }
391 /* Verify that we now have a controlling tty. */
392 fd = open(_PATH_TTY, O_WRONLY);
393 if (fd < 0)
394 error("open /dev/tty failed - could not set controlling tty: %.100s",
395 strerror(errno));
396 else {
397 close(fd);
398 }
399 #endif /* _CRAY */
400 }
401
402 #if 0 /* not in BasiliskII */
403 /* Changes the window size associated with the pty. */
404
405 void
406 pty_change_window_size(int ptyfd, int row, int col,
407 int xpixel, int ypixel)
408 {
409 struct winsize w;
410 w.ws_row = row;
411 w.ws_col = col;
412 w.ws_xpixel = xpixel;
413 w.ws_ypixel = ypixel;
414 (void) ioctl(ptyfd, TIOCSWINSZ, &w);
415 }
416
417 void
418 pty_setowner(struct passwd *pw, const char *ttyname)
419 {
420 struct group *grp;
421 gid_t gid;
422 mode_t mode;
423 struct stat st;
424
425 /* Determine the group to make the owner of the tty. */
426 grp = getgrnam("tty");
427 if (grp) {
428 gid = grp->gr_gid;
429 mode = S_IRUSR | S_IWUSR | S_IWGRP;
430 } else {
431 gid = pw->pw_gid;
432 mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
433 }
434
435 /*
436 * Change owner and mode of the tty as required.
437 * Warn but continue if filesystem is read-only and the uids match/
438 * tty is owned by root.
439 */
440 if (stat(ttyname, &st))
441 fatal("stat(%.100s) failed: %.100s", ttyname,
442 strerror(errno));
443
444 if (st.st_uid != pw->pw_uid || st.st_gid != gid) {
445 if (chown(ttyname, pw->pw_uid, gid) < 0) {
446 if (errno == EROFS &&
447 (st.st_uid == pw->pw_uid || st.st_uid == 0))
448 error("chown(%.100s, %d, %d) failed: %.100s",
449 ttyname, pw->pw_uid, gid,
450 strerror(errno));
451 else
452 fatal("chown(%.100s, %d, %d) failed: %.100s",
453 ttyname, pw->pw_uid, gid,
454 strerror(errno));
455 }
456 }
457
458 if ((st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != mode) {
459 if (chmod(ttyname, mode) < 0) {
460 if (errno == EROFS &&
461 (st.st_mode & (S_IRGRP | S_IROTH)) == 0)
462 error("chmod(%.100s, 0%o) failed: %.100s",
463 ttyname, mode, strerror(errno));
464 else
465 fatal("chmod(%.100s, 0%o) failed: %.100s",
466 ttyname, mode, strerror(errno));
467 }
468 }
469 }
470 #endif /* not in BasiliskII */