ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sshpty.c
Revision: 1.2
Committed: 2003-08-17T10:20:22Z (20 years, 10 months ago) by gbeauche
Content type: text/plain
Branch: MAIN
CVS Tags: nigel-build-19, nigel-build-16, nigel-build-17, nigel-build-15
Changes since 1.1: +1 -0 lines
Log Message:
#define log printf in B2 stubs

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