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

# User Rev Content
1 cebix 1.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 */