ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sshpty.c
Revision: 1.4
Committed: 2012-06-15T21:56:52Z (12 years, 4 months ago) by asvitkine
Content type: text/plain
Branch: MAIN
Changes since 1.3: +4 -0 lines
Log Message:
Hopefully make the HAVE_DEV_PTMX path work.

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